Skip to content

Commit

Permalink
Add message meaning challenge activity (#1706)
Browse files Browse the repository at this point in the history
* Add message meaning mode to toolbar

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: ggurdin <[email protected]>
Co-authored-by: ggurdin <[email protected]>
  • Loading branch information
4 people authored Feb 6, 2025
1 parent b98f2d3 commit e2ca788
Show file tree
Hide file tree
Showing 24 changed files with 421 additions and 79 deletions.
7 changes: 6 additions & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -4815,5 +4815,10 @@
"open": "Open",
"waitingForServer": "Waiting for server...",
"appIntroduction": "FluffyChat lets you chat with your friends across different messengers. Learn more at https://matrix.org or just tap *Continue*.",
"whatIsLemma": "What is the lemma?"
"whatIsLemma": "What is the lemma?",
"constructUseCorMmDesc": "Correct message meaning",
"constructUseIncMmDesc": "Incorrect message meaning",
"constructUseIgnMmDesc": "Ignored message meaning",
"clickForMeaningActivity": "Click here for a Meaning Challenge",
"meaning": "Meaning"
}
27 changes: 27 additions & 0 deletions lib/pangea/analytics_misc/construct_use_type_enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ enum ConstructUseTypeEnum {
/// User can select any emoji
em,

/// message meaning activity
corMM,
incMM,
ignMM,

/// not defined, likely a new construct introduced by choreo and not yet classified by an old version of the client
nan
}
Expand Down Expand Up @@ -121,6 +126,12 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
return L10n.of(context).constructUseEmojiDesc;
case ConstructUseTypeEnum.pvm:
return L10n.of(context).constructUsePvmDesc;
case ConstructUseTypeEnum.corMM:
return L10n.of(context).constructUseCorMmDesc;
case ConstructUseTypeEnum.incMM:
return L10n.of(context).constructUseIncMmDesc;
case ConstructUseTypeEnum.ignMM:
return L10n.of(context).constructUseIgnMmDesc;
case ConstructUseTypeEnum.nan:
return L10n.of(context).constructUseNanDesc;
}
Expand Down Expand Up @@ -161,6 +172,10 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
return ActivityTypeEnum.morphId.icon;
case ConstructUseTypeEnum.em:
return ActivityTypeEnum.emoji.icon;
case ConstructUseTypeEnum.corMM:
case ConstructUseTypeEnum.incMM:
case ConstructUseTypeEnum.ignMM:
return ActivityTypeEnum.messageMeaning.icon;
case ConstructUseTypeEnum.pvm:
return Icons.mic;
case ConstructUseTypeEnum.unk:
Expand Down Expand Up @@ -195,6 +210,7 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {

case ConstructUseTypeEnum.corIt:
case ConstructUseTypeEnum.em:
case ConstructUseTypeEnum.corMM:
return 1;

case ConstructUseTypeEnum.ignIt:
Expand All @@ -204,11 +220,13 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.ignHWL:
case ConstructUseTypeEnum.ignL:
case ConstructUseTypeEnum.ignM:
case ConstructUseTypeEnum.ignMM:
case ConstructUseTypeEnum.unk:
case ConstructUseTypeEnum.nan:
return 0;

case ConstructUseTypeEnum.ga:
case ConstructUseTypeEnum.incMM:
return -1;

case ConstructUseTypeEnum.incIt:
Expand Down Expand Up @@ -253,6 +271,9 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.corM:
case ConstructUseTypeEnum.incM:
case ConstructUseTypeEnum.ignM:
case ConstructUseTypeEnum.corMM:
case ConstructUseTypeEnum.incMM:
case ConstructUseTypeEnum.ignMM:
case ConstructUseTypeEnum.em:
case ConstructUseTypeEnum.nan:
return false;
Expand Down Expand Up @@ -288,6 +309,9 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.corM:
case ConstructUseTypeEnum.ignM:
case ConstructUseTypeEnum.incM:
case ConstructUseTypeEnum.corMM:
case ConstructUseTypeEnum.incMM:
case ConstructUseTypeEnum.ignMM:
case ConstructUseTypeEnum.em:
return LearningSkillsEnum.reading;
case ConstructUseTypeEnum.pvm:
Expand All @@ -313,6 +337,7 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.corL:
case ConstructUseTypeEnum.corM:
case ConstructUseTypeEnum.em:
case ConstructUseTypeEnum.corMM:
return AnalyticsSummaryEnum.numChoicesCorrect;

case ConstructUseTypeEnum.incIt:
Expand All @@ -322,6 +347,7 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.incHWL:
case ConstructUseTypeEnum.incL:
case ConstructUseTypeEnum.incM:
case ConstructUseTypeEnum.incMM:
return AnalyticsSummaryEnum.numChoicesIncorrect;

case ConstructUseTypeEnum.ignIt:
Expand All @@ -331,6 +357,7 @@ extension ConstructUseTypeExtension on ConstructUseTypeEnum {
case ConstructUseTypeEnum.ignHWL:
case ConstructUseTypeEnum.ignL:
case ConstructUseTypeEnum.ignM:
case ConstructUseTypeEnum.ignMM:
case ConstructUseTypeEnum.nan:
return null;
}
Expand Down
22 changes: 9 additions & 13 deletions lib/pangea/analytics_misc/message_analytics_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,7 @@ class MessageAnalyticsEntry {
}

void _popQueue() {
if (hasHiddenWordActivity) {
_activityQueue.removeAt(0);
}
if (_activityQueue.isNotEmpty) _activityQueue.removeAt(0);
}

void _filterQueue(ActivityTypeEnum activityType) {
Expand All @@ -123,6 +121,9 @@ class MessageAnalyticsEntry {
bool get hasHiddenWordActivity =>
nextActivity?.activityType.hiddenType ?? false;

bool get hasMessageMeaningActivity => _activityQueue
.any((a) => a.activityType == ActivityTypeEnum.messageMeaning);

int get numActivities => _activityQueue.length;

// /// If there are more than 4 tokens that can be heard, we don't want to do word focus listening
Expand All @@ -141,15 +142,12 @@ class MessageAnalyticsEntry {
}
}

/// Adds a word focus listening activity to the front of the queue
/// Add a message meaning activity to the front of the queue
/// And limits to _maxQueueLength activities
void addTokenToActivityQueue(
PangeaToken token, {
ActivityTypeEnum type = ActivityTypeEnum.wordMeaning,
}) {
void addMessageMeaningActivity() {
final entry = TargetTokensAndActivityType(
tokens: [token],
activityType: ActivityTypeEnum.wordMeaning,
tokens: _tokens,
activityType: ActivityTypeEnum.messageMeaning,
);
_pushQueue(entry);
}
Expand Down Expand Up @@ -204,9 +202,7 @@ class MessageAnalyticsEntry {
);
}

void onActivityComplete() {
_popQueue();
}
void onActivityComplete() => _popQueue();

void exitPracticeFlow() => _clearQueue();

Expand Down
13 changes: 9 additions & 4 deletions lib/pangea/events/event_wrappers/pangea_message_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -461,11 +461,11 @@ class PangeaMessageEvent {

RepresentationEvent? representationByLanguage(String langCode) =>
representations.firstWhereOrNull(
(element) => element.langCode == langCode,
(element) => element.langCode.split("-")[0] == langCode.split("-")[0],
);

int translationIndex(String langCode) => representations.indexWhere(
(element) => element.langCode == langCode,
(element) => element.langCode.split("-")[0] == langCode.split("-")[0],
);

String translationTextSafe(String langCode) {
Expand Down Expand Up @@ -596,7 +596,8 @@ class PangeaMessageEvent {

/// Should almost always be true. Useful in the case that the message
/// display rep has the langCode "unk"
bool get messageDisplayLangIsL2 => messageDisplayLangCode == l2Code;
bool get messageDisplayLangIsL2 =>
messageDisplayLangCode.split("-")[0] == l2Code?.split("-")[0];

String get messageDisplayLangCode {
final bool immersionMode = MatrixState
Expand Down Expand Up @@ -684,7 +685,11 @@ class PangeaMessageEvent {
bool debug = false,
}) =>
_practiceActivityEvents
.where((event) => event.practiceActivity.langCode == langCode)
.where(
(event) =>
event.practiceActivity.langCode.split("-")[0] ==
langCode.split("")[0],
)
.toList();

/// Returns a list of [PracticeActivityEvent] for the user's active l2.
Expand Down
42 changes: 39 additions & 3 deletions lib/pangea/events/models/pangea_token_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,30 @@ class PangeaToken {
);
}

List<OneConstructUse> allUses(
ConstructUseTypeEnum type,
ConstructUseMetaData metadata,
) {
final List<OneConstructUse> uses = [];
if (!lemma.saveVocab) return uses;

uses.add(toVocabUse(type, metadata));
for (final morphFeature in morph.keys) {
uses.add(
OneConstructUse(
useType: type,
lemma: morph[morphFeature],
form: text.content,
constructType: ConstructTypeEnum.morph,
metadata: metadata,
category: morphFeature,
),
);
}

return uses;
}

bool isActivityBasicallyEligible(
ActivityTypeEnum a, [
String? morphFeature,
Expand All @@ -238,6 +262,7 @@ class PangeaToken {
return lemma.saveVocab &&
text.content.toLowerCase() != lemma.text.toLowerCase();
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.messageMeaning:
return true;
case ActivityTypeEnum.morphId:
return morph.isNotEmpty && canGenerate;
Expand Down Expand Up @@ -299,13 +324,21 @@ class PangeaToken {
.any((u) => u == a.correctUse);
// Note that it matters less if they did morphId in general, than if they did it with the particular feature
case ActivityTypeEnum.morphId:
// TODO: investigate if we take out condition "|| morphTag == null", will we get the expected number of morph activities?
if (morphFeature == null || morphTag == null) {
debugger(when: kDebugMode);
return false;
}
return morphConstruct(morphFeature, morphTag)
.uses
.any((u) => u.useType == a.correctUse && u.form == text.content);
case ActivityTypeEnum.messageMeaning:
debugger(when: kDebugMode);
ErrorHandler.logError(
m: "should not call didActivitySuccessfully for ActivityTypeEnum.messageMeaning",
data: toJson(),
);
return true;
}
}

Expand All @@ -316,14 +349,15 @@ class PangeaToken {
]) {
switch (a) {
case ActivityTypeEnum.wordMeaning:
if (daysSinceLastUseByType(ActivityTypeEnum.wordMeaning) < 7) {
if (daysSinceLastUseByType(ActivityTypeEnum.wordMeaning) < 7 ||
daysSinceLastUseByType(ActivityTypeEnum.messageMeaning) < 7) {
return false;
}

if (isContentWord) {
return vocabConstruct.points < 3;
return vocabConstruct.points < 1;
} else if (canBeDefined) {
return vocabConstruct.points < 2;
return vocabConstruct.points < 1;
} else {
return false;
}
Expand All @@ -342,6 +376,7 @@ class PangeaToken {
// return _didActivitySuccessfully(ActivityTypeEnum.wordMeaning) &&
// daysSinceLastUseByType(a) > 7;
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.messageMeaning:
return true;
case ActivityTypeEnum.morphId:
if (morphFeature == null || morphTag == null) {
Expand Down Expand Up @@ -407,6 +442,7 @@ class PangeaToken {
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.wordFocusListening:
case ActivityTypeEnum.hiddenWordListening:
case ActivityTypeEnum.messageMeaning:
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extension LanguageLevelTypeEnumExtension on LanguageLevelTypeEnum {
String get string {
switch (this) {
case LanguageLevelTypeEnum.preA1:
return 'Pre-A1';
return 'PREA1';
case LanguageLevelTypeEnum.a1:
return 'A1';
case LanguageLevelTypeEnum.a2:
Expand Down Expand Up @@ -65,6 +65,7 @@ extension LanguageLevelTypeEnumExtension on LanguageLevelTypeEnum {
static LanguageLevelTypeEnum fromString(String? value) {
switch (value) {
case 'PREA1':
case 'PRE-A1':
case 'Pre-A1':
return LanguageLevelTypeEnum.preA1;
case 'A1':
Expand Down
19 changes: 18 additions & 1 deletion lib/pangea/toolbar/enums/activity_type_enum.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum ActivityTypeEnum {
lemmaId,
emoji,
morphId,
// correctionPuzzle,
messageMeaning, // TODO: Add to L10n
}

extension ActivityTypeExtension on ActivityTypeEnum {
Expand All @@ -31,6 +31,8 @@ extension ActivityTypeExtension on ActivityTypeEnum {
return 'emoji';
case ActivityTypeEnum.morphId:
return 'morph_id';
case ActivityTypeEnum.messageMeaning:
return 'message_meaning'; // TODO: Add to L10n
}
}

Expand All @@ -41,6 +43,7 @@ extension ActivityTypeExtension on ActivityTypeEnum {
case ActivityTypeEnum.lemmaId:
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.morphId:
case ActivityTypeEnum.messageMeaning:
return false;
case ActivityTypeEnum.hiddenWordListening:
return true;
Expand All @@ -53,6 +56,7 @@ extension ActivityTypeExtension on ActivityTypeEnum {
case ActivityTypeEnum.lemmaId:
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.morphId:
case ActivityTypeEnum.messageMeaning:
return false;
case ActivityTypeEnum.wordFocusListening:
case ActivityTypeEnum.hiddenWordListening:
Expand Down Expand Up @@ -83,6 +87,8 @@ extension ActivityTypeExtension on ActivityTypeEnum {
return ActivityTypeEnum.emoji;
case 'morph_id':
return ActivityTypeEnum.morphId;
case 'message_meaning':
return ActivityTypeEnum.messageMeaning; // TODO: Add to L10n
default:
throw Exception('Unknown activity type: $split');
}
Expand Down Expand Up @@ -122,6 +128,12 @@ extension ActivityTypeExtension on ActivityTypeEnum {
ConstructUseTypeEnum.incM,
ConstructUseTypeEnum.ignM,
];
case ActivityTypeEnum.messageMeaning:
return [
ConstructUseTypeEnum.corMM,
ConstructUseTypeEnum.incMM,
ConstructUseTypeEnum.ignMM,
]; // TODO: Add to L10n
}
}

Expand All @@ -139,6 +151,8 @@ extension ActivityTypeExtension on ActivityTypeEnum {
return ConstructUseTypeEnum.em;
case ActivityTypeEnum.morphId:
return ConstructUseTypeEnum.corM;
case ActivityTypeEnum.messageMeaning:
return ConstructUseTypeEnum.corMM;
}
}

Expand All @@ -150,6 +164,7 @@ extension ActivityTypeExtension on ActivityTypeEnum {
case ActivityTypeEnum.hiddenWordListening:
case ActivityTypeEnum.lemmaId:
case ActivityTypeEnum.emoji:
case ActivityTypeEnum.messageMeaning:
return (id) => id.type == ConstructTypeEnum.vocab;
case ActivityTypeEnum.morphId:
return (id) => id.type == ConstructTypeEnum.morph;
Expand All @@ -169,6 +184,8 @@ extension ActivityTypeExtension on ActivityTypeEnum {
return Icons.emoji_emotions;
case ActivityTypeEnum.morphId:
return Icons.format_shapes;
case ActivityTypeEnum.messageMeaning:
return Icons.star; // TODO: Add to L10n
}
}
}
Loading

0 comments on commit e2ca788

Please sign in to comment.