diff --git a/lib/pangea/analytics_practice/analytics_practice_page.dart b/lib/pangea/analytics_practice/analytics_practice_page.dart index 43e04099e..b8015723f 100644 --- a/lib/pangea/analytics_practice/analytics_practice_page.dart +++ b/lib/pangea/analytics_practice/analytics_practice_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; +import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_data/analytics_updater_mixin.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/example_message_util.dart'; @@ -12,10 +13,12 @@ import 'package:fluffychat/pangea/analytics_practice/analytics_practice_session_ import 'package:fluffychat/pangea/analytics_practice/analytics_practice_ui_controller.dart'; import 'package:fluffychat/pangea/analytics_practice/analytics_practice_view.dart'; import 'package:fluffychat/pangea/common/utils/async_state.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/common/widgets/feedback_dialog.dart'; import 'package:fluffychat/pangea/languages/language_model.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; -import 'package:fluffychat/pangea/practice_activities/message_activity_request.dart'; import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; +import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; import 'package:fluffychat/widgets/matrix.dart'; class SelectedMorphChoice { @@ -304,23 +307,44 @@ class AnalyticsPracticeState extends State Future startNextActivity() async { _sessionController.completeActivity(); progress.value = _sessionController.progress; - - _sessionController.session?.isComplete == true - ? await _completeSession() - : await _continueSession(); + await _continueSession(); } - Future skipActivity(MessageActivityRequest request) async { + Future skipActivity(PracticeTarget target) async { // Record a 0 XP use so that activity isn't chosen again soon _sessionController.skipActivity(); progress.value = _sessionController.progress; await _analyticsController.addSkippedActivityAnalytics( - request.target, + target, _l2!.langCodeShort, ); } + Future flagActivity( + MultipleChoicePracticeActivityModel activity, + ) async { + final feedback = await showDialog( + context: context, + builder: (context) { + return FeedbackDialog( + title: L10n.of(context).feedbackTitle, + onSubmit: Navigator.of(context).pop, + scrollable: false, + ); + }, + ); + + if (feedback == null || feedback.isEmpty) return; + ErrorHandler.logError( + e: 'Practice activity flagged', + data: {'activity': activity.toJson(), 'feedback': feedback}, + ); + + await skipActivity(activity.practiceTarget); + await _continueSession(); + } + @override Widget build(BuildContext context) => AnalyticsPracticeView(this); } diff --git a/lib/pangea/analytics_practice/analytics_practice_session_controller.dart b/lib/pangea/analytics_practice/analytics_practice_session_controller.dart index f04856051..a05ef1a1e 100644 --- a/lib/pangea/analytics_practice/analytics_practice_session_controller.dart +++ b/lib/pangea/analytics_practice/analytics_practice_session_controller.dart @@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/practice_activities/message_activity_request.dart'; import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; import 'package:fluffychat/pangea/practice_activities/practice_generation_repo.dart'; +import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -95,7 +96,7 @@ class PracticeSessionController { } Future _initActivityData( - Future Function(MessageActivityRequest) onSkip, + Future Function(PracticeTarget) onSkip, Future Function(MultipleChoicePracticeActivityModel) onFetch, ) async { final requests = activityRequests; @@ -106,7 +107,7 @@ class PracticeSessionController { _fillActivityQueue(requests.skip(i + 1).toList(), onSkip, onFetch); return res; } catch (e) { - await onSkip(requests[i]); + await onSkip(requests[i].target); // Try next request continue; } @@ -116,7 +117,7 @@ class PracticeSessionController { Future _fillActivityQueue( List requests, - Future Function(MessageActivityRequest) onSkip, + Future Function(PracticeTarget) onSkip, Future Function(MultipleChoicePracticeActivityModel) onFetch, ) async { for (final request in requests) { @@ -127,7 +128,7 @@ class PracticeSessionController { completer.complete(res); } catch (e) { completer.completeError(e); - await onSkip(request); + await onSkip(request.target); } } } @@ -149,7 +150,7 @@ class PracticeSessionController { } Future getNextActivity( - Future Function(MessageActivityRequest) onSkip, + Future Function(PracticeTarget) onSkip, Future Function(MultipleChoicePracticeActivityModel) onFetch, ) async { final session = this.session; diff --git a/lib/pangea/analytics_practice/ongoing_activity_session_view.dart b/lib/pangea/analytics_practice/ongoing_activity_session_view.dart index 9da9ac173..656db9b5d 100644 --- a/lib/pangea/analytics_practice/ongoing_activity_session_view.dart +++ b/lib/pangea/analytics_practice/ongoing_activity_session_view.dart @@ -42,6 +42,15 @@ class OngoingActivitySessionView extends StatelessWidget { Expanded( child: ListView( children: [ + Align( + alignment: Alignment.centerRight, + child: IconButton( + icon: Icon(Icons.flag_outlined), + onPressed: activity != null + ? () => controller.flagActivity(activity) + : null, + ), + ), //Hints counter bar for grammar activities only if (controller.widget.type == ConstructTypeEnum.morph) Padding( diff --git a/lib/utils/feedback_dialog.dart b/lib/utils/feedback_dialog.dart deleted file mode 100644 index dbb06b362..000000000 --- a/lib/utils/feedback_dialog.dart +++ /dev/null @@ -1,71 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/l10n/l10n.dart'; -import '../pangea/bot/widgets/bot_face_svg.dart'; - -Future showFeedbackDialog( - BuildContext context, - Widget offendingContent, - void Function(String) submitFeedback, -) { - final TextEditingController feedbackController = TextEditingController(); - return showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: Text( - L10n.of(context).reportContentIssueTitle, - textAlign: TextAlign.center, - ), - content: SingleChildScrollView( - child: Container( - constraints: const BoxConstraints(maxWidth: 300), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const BotFace(width: 60, expression: BotExpression.addled), - const SizedBox(height: 10), - Text(L10n.of(context).reportContentIssueDescription), - const SizedBox(height: 10), - Container( - padding: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.0), - border: Border.all(color: AppConfig.warning), - ), - child: offendingContent, - ), - const SizedBox(height: 10), - TextField( - controller: feedbackController, - decoration: InputDecoration( - labelText: L10n.of(context).feedback, - border: const OutlineInputBorder(), - ), - maxLines: 4, - ), - ], - ), - ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); // Close the dialog - }, - child: Text(L10n.of(context).cancel), - ), - ElevatedButton( - onPressed: () { - // Call the additional callback function - submitFeedback(feedbackController.text); - Navigator.of(context).pop(); // Close the dialog - }, - child: Text(L10n.of(context).submit), - ), - ], - ); - }, - ); -}