fix(reading_assistance): register end of activity

pull/1817/head
wcjord 8 months ago
parent 0321d20f44
commit 32ab738477

@ -1,11 +1,5 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pages/chat/events/video_player.dart';
import 'package:fluffychat/pangea/choreographer/widgets/igc/pangea_rich_text.dart';
@ -17,6 +11,11 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart
import 'package:fluffychat/pangea/toolbar/widgets/message_token_text.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_toolbar_selection_area.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_linkify/flutter_linkify.dart';
import 'package:matrix/matrix.dart';
import '../../../config/app_config.dart';
import '../../../utils/platform_infos.dart';
import '../../../utils/url_launcher.dart';
@ -385,7 +384,8 @@ class MessageContent extends StatelessWidget {
isHighlighted: (PangeaToken token) =>
overlayController?.toolbarMode.associatedActivityType !=
null &&
overlayController?.practiceSelection?.hasActivity(
overlayController?.practiceSelection
?.hasActiveActivityByToken(
overlayController!
.toolbarMode.associatedActivityType!,
token,

@ -74,6 +74,10 @@ class PracticeActivityModel {
return;
}
// final ConstructIdentifier? cId = activityType == ActivityTypeEnum.morphId
// ? morphFeature ?= null ? token.getMorphTag(morphFeature) : null
// : choice.form.cId;
if (practiceTarget.record.hasTextResponse(choice.choiceContent) ||
isComplete) {
// the user has already selected this choice
@ -221,31 +225,6 @@ class PracticeActivityModel {
callback();
}
bool? wasCorrectChoice(String choice) {
for (final response in practiceTarget.record.responses) {
if (response.text == choice) {
return multipleChoiceContent?.answers
.any((answer) => answer.toLowerCase() == choice.toLowerCase());
}
}
return null;
}
/// 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.text == choice.choiceContent && response.isCorrect) {
return true;
}
}
for (final response in practiceTarget.record.responses) {
if (response.text == choice.choiceContent) {
return false;
}
}
return null;
}
PracticeRecord get record => practiceTarget.record;
PracticeTarget get practiceTarget => PracticeTarget(

@ -225,12 +225,12 @@ class PracticeSelection {
);
}
bool hasActivity(
ActivityTypeEnum a, [
PangeaToken? t,
bool hasActiveActivityByToken(
ActivityTypeEnum a,
PangeaToken t, [
MorphFeaturesEnum? morph,
]) =>
getSelection(a, t, morph) != null;
getSelection(a, t, morph)?.isCompleteByToken(t, morph) == false;
/// Add a message meaning activity to the front of the queue
/// And limits to _maxQueueLength activities

@ -1,10 +1,14 @@
import 'package:flutter/foundation.dart';
import 'dart:developer';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.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_choice.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
@ -94,4 +98,49 @@ class PracticeTarget {
.any((res) => res.cId == t.vocabConstructID && res.isCorrect),
);
}
bool isCompleteByToken(PangeaToken token, [MorphFeaturesEnum? morph]) {
final ConstructIdentifier? cId =
morph == null ? token.vocabConstructID : token.morphIdByFeature(morph);
if (cId == null) {
debugger(when: kDebugMode);
ErrorHandler.logError(
m: "isCompleteByToken: cId is null for token ${token.text.content}",
data: {
"t": token.toJson(),
"morph": morph?.name,
},
);
return false;
}
return record.responses.any(
(res) => res.cId == token.vocabConstructID && res.isCorrect,
);
}
bool? wasCorrectChoice(String choice) {
for (final response in record.responses) {
if (response.text == choice) {
return response.isCorrect;
}
}
return null;
}
/// if any of the choices were correct, return true
/// if all of the choices were incorrect, return false
/// if null, it means the user has not yet responded with that choice
bool? wasCorrectMatch(PracticeChoice choice) {
for (final response in record.responses) {
if (response.text == choice.choiceContent && response.isCorrect) {
return true;
}
}
for (final response in record.responses) {
if (response.text == choice.choiceContent) {
return false;
}
}
return null;
}
}

@ -1,8 +1,4 @@
import 'package:flutter/material.dart';
import 'package:collection/collection.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/choreographer/widgets/choice_animation.dart';
import 'package:fluffychat/pangea/constructs/construct_form.dart';
@ -15,6 +11,8 @@ import 'package:fluffychat/pangea/practice_activities/practice_activity_model.da
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/message_morph_choice_item.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
// this widget will handle the content of the input bar when mode == MessageMode.wordMorph
@ -111,42 +109,45 @@ class MessageMorphInputBarContentState
runAlignment: WrapAlignment.center,
spacing: spacing,
runSpacing: spacing,
children: widget.activity.multipleChoiceContent!.choices
.mapIndexed(
(index, choice) => ChoiceAnimationWidget(
isSelected: selectedTag == choice,
isCorrect: widget.activity.wasCorrectChoice(choice) ?? false,
child: MessageMorphChoiceItem(
cId: ConstructIdentifier(
lemma: choice,
type: ConstructTypeEnum.morph,
category: morph.name,
),
onTap: () {
setState(() => selectedTag = choice);
widget.activity.onMultipleChoiceSelect(
token,
PracticeChoice(
choiceContent: choice,
form: ConstructForm(
cId: widget.activity.targetTokens.first
.morphIdByFeature(
widget.activity.morphFeature!,
)!,
form: token.text.content,
),
),
widget.pangeaMessageEvent,
() => overlay.setState(() {}),
);
},
isSelected: selectedTag == choice,
isGold: widget.activity.wasCorrectChoice(choice),
children: widget.activity.multipleChoiceContent!.choices.mapIndexed(
(index, choice) {
final wasCorrect =
widget.activity.practiceTarget.wasCorrectChoice(choice);
return ChoiceAnimationWidget(
isSelected: selectedTag == choice,
isCorrect: wasCorrect,
child: MessageMorphChoiceItem(
cId: ConstructIdentifier(
lemma: choice,
type: ConstructTypeEnum.morph,
category: morph.name,
),
onTap: () {
setState(() => selectedTag = choice);
widget.activity.onMultipleChoiceSelect(
token,
PracticeChoice(
choiceContent: choice,
form: ConstructForm(
cId: widget.activity.targetTokens.first
.morphIdByFeature(
widget.activity.morphFeature!,
)!,
form: token.text.content,
),
),
widget.pangeaMessageEvent,
() => overlay.setState(() {}),
);
},
isSelected: selectedTag == choice,
isGold: wasCorrect,
),
)
.toList(),
);
},
).toList(),
),
// SizedBox(
// height: 50,

@ -83,12 +83,14 @@ class MatchActivityCard extends StatelessWidget {
runSpacing: 4.0,
children: activity.matchContent!.choices.map(
(PracticeChoice cf) {
final bool? wasCorrect =
currentActivity.practiceTarget.wasCorrectMatch(cf);
return ChoiceAnimationWidget(
isSelected: overlayController.selectedChoice == cf,
isCorrect: currentActivity.wasCorrectMatch(cf),
isCorrect: wasCorrect,
child: PracticeMatchItem(
isSelected: overlayController.selectedChoice == cf,
isCorrect: currentActivity.wasCorrectMatch(cf),
isCorrect: wasCorrect,
constructForm: cf,
content: choiceDisplayContent(cf.choiceContent, fontSize),
audioContent:

@ -1,13 +1,7 @@
import 'dart:async';
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:collection/collection.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
@ -31,6 +25,10 @@ import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/morph_sel
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_positioner.dart';
import 'package:fluffychat/pangea/toolbar/widgets/reading_assistance_content.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:matrix/matrix.dart';
/// Controls data at the top level of the toolbar (mainly token / toolbar mode selection)
class MessageSelectionOverlay extends StatefulWidget {
@ -503,7 +501,7 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
}
/// we don't want to associate the audio with the text in this mode
if (practiceSelection?.hasActivity(
if (practiceSelection?.hasActiveActivityByToken(
ActivityTypeEnum.wordFocusListening,
token,
) ==

@ -1,11 +1,5 @@
import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_model.dart';
import 'package:fluffychat/pangea/analytics_misc/text_loading_shimmer.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
@ -18,6 +12,10 @@ import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_zoom_activity_button.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:material_symbols_icons/symbols.dart';
class LemmaMeaningWidget extends StatefulWidget {
final ConstructUses constructUse;
@ -121,8 +119,10 @@ class LemmaMeaningWidgetState extends State<LemmaMeaningWidget> {
Widget build(BuildContext context) {
if (widget.token != null &&
widget.controller?.practiceSelection != null &&
widget.controller!.practiceSelection!
.hasActivity(ActivityTypeEnum.wordMeaning, widget.token!)) {
widget.controller!.practiceSelection!.hasActiveActivityByToken(
ActivityTypeEnum.wordMeaning,
widget.token!,
)) {
return WordZoomActivityButton(
icon: const Icon(Symbols.dictionary),
isSelected: widget.controller?.toolbarMode == MessageMode.wordMeaning,

@ -191,15 +191,15 @@ class LemmaWidgetState extends State<LemmaWidget> {
isSelected:
MessageMode.listening == widget.overlayController?.toolbarMode,
baseOpacity: 0.4,
callbackOverride:
widget.overlayController?.practiceSelection?.hasActivity(
MessageMode.listening.associatedActivityType!,
widget.token,
) ==
true
? () => widget.overlayController
?.updateToolbarMode(MessageMode.listening)
: null,
callbackOverride: widget.overlayController?.practiceSelection
?.hasActiveActivityByToken(
MessageMode.listening.associatedActivityType!,
widget.token,
) ==
true
? () => widget.overlayController
?.updateToolbarMode(MessageMode.listening)
: null,
uniqueID: "lemma-content-${widget.token.text.content}",
),
],

@ -1,7 +1,3 @@
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/morphs/get_grammar_copy.dart';
import 'package:fluffychat/pangea/morphs/morph_features_enum.dart';
@ -11,6 +7,8 @@ import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/morph_selection.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_zoom_activity_button.dart';
import 'package:flutter/material.dart';
import 'package:material_symbols_icons/symbols.dart';
class MorphologicalListItem extends StatelessWidget {
final MorphFeaturesEnum morphFeature;
@ -25,7 +23,7 @@ class MorphologicalListItem extends StatelessWidget {
});
bool get shouldDoActivity =>
overlayController.practiceSelection?.hasActivity(
overlayController.practiceSelection?.hasActiveActivityByToken(
ActivityTypeEnum.morphId,
token,
morphFeature,

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
@ -18,6 +16,7 @@ import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_widget.dart';
import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/morphological_list_item.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
class WordZoomWidget extends StatelessWidget {
final PangeaToken token;
@ -38,7 +37,7 @@ class WordZoomWidget extends StatelessWidget {
void onEditDone() => overlayController.initializeTokensAndMode();
bool get hasEmojiActivity =>
overlayController.practiceSelection?.hasActivity(
overlayController.practiceSelection?.hasActiveActivityByToken(
ActivityTypeEnum.emoji,
_selectedToken,
) ==
@ -170,15 +169,15 @@ class WordZoomWidget extends StatelessWidget {
isSelected:
MessageMode.listening == overlayController.toolbarMode,
baseOpacity: 0.4,
callbackOverride:
overlayController.practiceSelection?.hasActivity(
MessageMode.listening.associatedActivityType!,
_selectedToken,
) ==
true
? () => overlayController
.updateToolbarMode(MessageMode.listening)
: null,
callbackOverride: overlayController.practiceSelection
?.hasActiveActivityByToken(
MessageMode.listening.associatedActivityType!,
_selectedToken,
) ==
true
? () => overlayController
.updateToolbarMode(MessageMode.listening)
: null,
uniqueID: "word-zoom-audio-${_selectedToken.text.content}",
),
],

Loading…
Cancel
Save