diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 6c2672b35..18b2767a0 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -1,9 +1,7 @@ +import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:flutter/material.dart'; - import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/common/config/environment.dart'; - abstract class AppConfig { // #Pangea // static String _applicationName = 'FluffyChat'; @@ -55,7 +53,8 @@ abstract class AppConfig { // static const Color primaryColorLight = Color(0xFFCCBDEA); static const Color primaryColor = Color(0xFF8560E0); static const Color primaryColorLight = Color(0xFFDBC9FF); - static const Color secondaryColor = Color(0xFF41a2bc); + // static const Color secondaryColor = Color(0xFF41a2bc); + static const Color secondaryColor = Color.fromARGB(255, 253, 191, 1); static const Color activeToggleColor = Color(0xFF33D057); static const Color success = Color(0xFF33D057); static const Color warning = Color.fromARGB(255, 210, 124, 12); diff --git a/lib/config/themes.dart b/lib/config/themes.dart index c90694037..c06250291 100644 --- a/lib/config/themes.dart +++ b/lib/config/themes.dart @@ -68,6 +68,8 @@ abstract class FluffyThemes { seedColor: seed ?? AppConfig.colorSchemeSeed ?? Theme.of(context).colorScheme.primary, + // primary: AppConfig.primaryColor, + // secondary: AppConfig.gold, ); final isColumnMode = FluffyThemes.isColumnMode(context); return ThemeData( diff --git a/lib/pangea/instructions/instructions_inline_tooltip.dart b/lib/pangea/instructions/instructions_inline_tooltip.dart index e90842482..c07f0dda9 100644 --- a/lib/pangea/instructions/instructions_inline_tooltip.dart +++ b/lib/pangea/instructions/instructions_inline_tooltip.dart @@ -1,10 +1,8 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pangea/instructions/instructions_enum.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; class InstructionsInlineTooltip extends StatefulWidget { final InstructionsEnum instructionsEnum; @@ -103,7 +101,7 @@ class InstructionsInlineTooltipState extends State decoration: BoxDecoration( borderRadius: BorderRadius.circular(AppConfig.borderRadius), color: Color.alphaBlend( - Colors.black.withAlpha(70), + Theme.of(context).colorScheme.surface.withAlpha(70), AppConfig.gold, ), ), diff --git a/lib/pangea/practice_activities/practice_activity_model.dart b/lib/pangea/practice_activities/practice_activity_model.dart index a9a97231d..d70972a79 100644 --- a/lib/pangea/practice_activities/practice_activity_model.dart +++ b/lib/pangea/practice_activities/practice_activity_model.dart @@ -1,13 +1,7 @@ import 'dart:developer'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - import 'package:collection/collection.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; - -import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; +import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; @@ -23,6 +17,10 @@ import 'package:fluffychat/pangea/practice_activities/practice_record.dart'; import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; import 'package:fluffychat/pangea/practice_activities/relevant_span_display_details.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; class PracticeActivityModel { List targetTokens; @@ -95,9 +93,9 @@ class PracticeActivityModel { score: isCorrect ? 1 : 0, ); - debugPrint( - "onMultipleChoiceSelect: ${choice.form} ${responseUseType(choice)}", - ); + // debugPrint( + // "onMultipleChoiceSelect: ${choice.form} ${responseUseType(choice)}", + // ); MatrixState.pangeaController.putAnalytics.setState( AnalyticsStream( @@ -105,7 +103,7 @@ class PracticeActivityModel { roomId: event?.room.id, constructs: [ OneConstructUse( - useType: responseUseType(choice)!, + useType: practiceTarget.record.responses.last.useType(activityType), lemma: choice.form.cId.lemma, constructType: choice.form.cId.type, metadata: ConstructUseMetaData( @@ -133,8 +131,12 @@ class PracticeActivityModel { ) { // the user has already selected this choice // so we don't want to record it again - if (practiceTarget.record.hasTextResponse(choice.choiceContent) || + if (practiceTarget.record.alreadyHasMatchResponse( + token.vocabConstructID, + choice.choiceContent, + ) || isComplete) { + debugger(when: kDebugMode); return; } @@ -144,8 +146,12 @@ class PracticeActivityModel { (answer) => answer.toLowerCase() == choice.choiceContent.toLowerCase(), ); } else if (matchContent != null) { - isCorrect = matchContent!.matchInfo[token.vocabForm]! - .contains(choice.choiceContent); + // we check to see if it's in the list of acceptable answers + // rather than if the vocabForm is the same because an emoji + // could be in multiple constructs so there could be multiple answers + final answers = matchContent!.matchInfo[token.vocabForm]; + debugger(when: answers == null && kDebugMode); + isCorrect = answers!.contains(choice.choiceContent); } else { debugger(when: kDebugMode); ErrorHandler.logError( @@ -156,11 +162,11 @@ class PracticeActivityModel { return; } - // NOTE: the response is associated with the contructId of the choice, not the selected token + // NOTE: the response is associated with the contructId of the selected token, not the choice // example: the user selects the word "cat" to match with the emoji 🐶 - // the response is associated with correct word "dog", not the word "cat" + // the response is associated with incorrect word "cat", not the word "dog" practiceTarget.record.addResponse( - cId: choice.form.cId, + cId: token.vocabConstructID, text: choice.choiceContent, target: practiceTarget, score: isCorrect ? 1 : 0, @@ -174,15 +180,16 @@ class PracticeActivityModel { roomId: event?.room.id, constructs: [ OneConstructUse( - useType: responseUseType(choice)!, - lemma: choice.form.cId.lemma, - constructType: choice.form.cId.type, + useType: + practiceTarget.record.responses.last.useType(activityType), + lemma: token.lemma.text, + constructType: ConstructTypeEnum.vocab, metadata: ConstructUseMetaData( roomId: event?.room.id, timeStamp: DateTime.now(), eventId: event?.eventId, ), - category: choice.form.cId.category, + category: token.pos, // in the case of a wrong answer, the cId doesn't match the token form: token.text.content, ), @@ -226,27 +233,18 @@ class PracticeActivityModel { /// if null, it means the user has not yet responded with that choice bool? wasCorrectMatch(PracticeChoice choice) { for (final response in practiceTarget.record.responses) { - if (response.cId == choice.form.cId && response.isCorrect) { + if (response.text == choice.choiceContent && response.isCorrect) { return true; } } for (final response in practiceTarget.record.responses) { - if (response.cId == choice.form.cId) { + if (response.text == choice.choiceContent) { return false; } } return null; } - ConstructUseTypeEnum? responseUseType(PracticeChoice choice) { - for (final response in practiceTarget.record.responses) { - if (response.cId == choice.form.cId) { - return response.useType(activityType); - } - } - return null; - } - PracticeRecord get record => practiceTarget.record; PracticeTarget get practiceTarget => PracticeTarget( diff --git a/lib/pangea/practice_activities/practice_generation_repo.dart b/lib/pangea/practice_activities/practice_generation_repo.dart index 68eabc6be..a94d91233 100644 --- a/lib/pangea/practice_activities/practice_generation_repo.dart +++ b/lib/pangea/practice_activities/practice_generation_repo.dart @@ -2,12 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:developer'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import 'package:http/http.dart'; -import 'package:matrix/matrix.dart'; - import 'package:fluffychat/pangea/common/config/environment.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/network/requests.dart'; @@ -25,6 +19,10 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da import 'package:fluffychat/pangea/practice_activities/word_focus_listening_generator.dart'; import 'package:fluffychat/pangea/toolbar/event_wrappers/practice_activity_event.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; +import 'package:matrix/matrix.dart'; /// Represents an item in the completion cache. class _RequestCacheItem { @@ -173,7 +171,6 @@ class PracticeRepo { // TODO resolve some wierdness here whereby the activity can be null but then... it's not final eventCompleter = Completer(); - debugPrint('Activity generated: ${res.activity.toJson()}'); if (event != null) { _sendAndPackageEvent(res.activity, event).then((event) { eventCompleter.complete(event); diff --git a/lib/pangea/practice_activities/practice_match.dart b/lib/pangea/practice_activities/practice_match.dart index 99984e468..a811fb076 100644 --- a/lib/pangea/practice_activities/practice_match.dart +++ b/lib/pangea/practice_activities/practice_match.dart @@ -1,7 +1,7 @@ import 'package:collection/collection.dart'; - import 'package:fluffychat/pangea/constructs/construct_form.dart'; import 'package:fluffychat/pangea/practice_activities/practice_choice.dart'; +import 'package:flutter/material.dart'; class PracticeMatchActivity { /// The constructIdenfifiers involved in the activity @@ -13,6 +13,11 @@ class PracticeMatchActivity { PracticeMatchActivity({ required this.matchInfo, }) { + for (final ith in matchInfo.entries) { + debugPrint( + 'Construct: ${ith.key}, Forms: ${ith.value}', + ); + } // if there are multiple forms for a construct, pick one to display // each cosntruct will have ~3 forms // sometimes a form could be in multiple constructs @@ -21,13 +26,17 @@ class PracticeMatchActivity { // either from that construct's options, or returning to the previous construct // and picking a different form from there for (final ith in matchInfo.entries) { - for (final acceptableAnswer in ith.value) { + for (int i = 0; i < ith.value.length; i++) { + final String acceptableAnswer = ith.value[i]; if (!choices .any((element) => element.choiceContent == acceptableAnswer)) { choices.add( PracticeChoice(choiceContent: acceptableAnswer, form: ith.key), ); - break; + debugPrint( + 'Added choice: ${choices.last.choiceContent} for form: ${choices.last.form.form}', + ); + i = ith.value.length; // break out of the loop } // TODO: if none found, we can probably pick a different form for the other one } diff --git a/lib/pangea/practice_activities/practice_record.dart b/lib/pangea/practice_activities/practice_record.dart index 20756ce9c..66ee3beab 100644 --- a/lib/pangea/practice_activities/practice_record.dart +++ b/lib/pangea/practice_activities/practice_record.dart @@ -5,8 +5,6 @@ import 'dart:developer'; -import 'package:flutter/foundation.dart'; - import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; @@ -16,6 +14,7 @@ import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart'; import 'package:fluffychat/pangea/practice_activities/practice_record_repo.dart'; import 'package:fluffychat/pangea/practice_activities/practice_target.dart'; +import 'package:flutter/foundation.dart'; class PracticeRecord { late DateTime createdAt; @@ -72,6 +71,15 @@ class PracticeRecord { return responses.any((element) => element.text == text); } + bool alreadyHasMatchResponse( + ConstructIdentifier cId, + String text, + ) { + return responses.any( + (element) => element.cId == cId && element.text == text, + ); + } + /// [target] needed for saving the record, little funky /// [cId] identifies the construct in the case of match activities which have multiple /// [text] is the user's response @@ -111,6 +119,7 @@ class PracticeRecord { score: score, ), ); + debugPrint("responses: ${responses.map((r) => r.toJson())}"); PracticeRecordRepo.save(target, this); } catch (e) { @@ -156,6 +165,9 @@ class PracticeRecord { } class ActivityRecordResponse { + /// the cId of the construct that the user attached their response to + /// ie. in the "I like the dog" if the user erroneously attaches a dog emoji to the word like + /// then the cId is that of 'like ConstructIdentifier cId; // the user's response // has nullable string, nullable audio bytes, nullable image bytes, and timestamp diff --git a/lib/pangea/practice_activities/practice_target.dart b/lib/pangea/practice_activities/practice_target.dart index 6329738b4..aafc14c84 100644 --- a/lib/pangea/practice_activities/practice_target.dart +++ b/lib/pangea/practice_activities/practice_target.dart @@ -1,10 +1,9 @@ -import 'package:flutter/foundation.dart'; - import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/practice_activities/practice_record.dart'; import 'package:fluffychat/pangea/practice_activities/practice_record_repo.dart'; +import 'package:flutter/foundation.dart'; /// Picks which tokens to do activities on and what types of activities to do /// Caches result so that we don't have to recompute it @@ -90,7 +89,8 @@ class PracticeTarget { } return tokens.every( - (t) => record.responses.any((res) => res.cId == t.vocabConstructID), + (t) => record.responses + .any((res) => res.cId == t.vocabConstructID && res.isCorrect), ); } }