diff --git a/lib/pages/chat/events/html_message.dart b/lib/pages/chat/events/html_message.dart
index 43497b0dc..f0e1f2838 100644
--- a/lib/pages/chat/events/html_message.dart
+++ b/lib/pages/chat/events/html_message.dart
@@ -446,8 +446,10 @@ class HtmlMessage extends StatelessWidget {
enabled: token.lemma.saveVocab,
targetId: overlayController!.tokenEmojiPopupKey(token),
selectModeNotifier: overlayController!.selectedMode,
- selectedTokenNotifier:
- overlayController!.selectedTokenNotifier,
+ onTap: () =>
+ overlayController!.onClickOverlayMessageToken(token),
+ constructEmojiNotifier: overlayController!
+ .selectModeController.constructEmojiNotifier,
),
if (renderer.showCenterStyling &&
token != null &&
@@ -946,9 +948,10 @@ class HtmlMessage extends StatelessWidget {
// Use TokenEmojiButton to ensure consistent vertical alignment for non-token elements (e.g., emojis) in practice mode.
TokenEmojiButton(
selectModeNotifier: overlayController!.selectedMode,
- selectedTokenNotifier:
- overlayController!.selectedTokenNotifier,
+ onTap: () {},
enabled: false,
+ constructEmojiNotifier: overlayController!
+ .selectModeController.constructEmojiNotifier,
),
RichText(
text: TextSpan(
diff --git a/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart b/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart
index 9e1b1d858..575fe1839 100644
--- a/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart
+++ b/lib/pangea/analytics_misc/lemma_emoji_setter_mixin.dart
@@ -10,7 +10,7 @@ import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/instructions/instructions_enum.dart';
import 'package:fluffychat/widgets/matrix.dart';
-mixin LemmaEmojiSetter on State {
+mixin LemmaEmojiSetter {
Future setLemmaEmoji(
ConstructIdentifier constructId,
String emoji,
@@ -26,11 +26,13 @@ mixin LemmaEmojiSetter on State {
await constructId.setUserLemmaInfo(
constructId.userLemmaInfo.copyWith(emojis: [emoji]),
);
-
- _showSnackbar(constructId, emoji);
}
- void _showSnackbar(ConstructIdentifier constructId, String emoji) {
+ void showLemmaEmojiSnackbar(
+ BuildContext context,
+ ConstructIdentifier constructId,
+ String emoji,
+ ) {
if (InstructionsEnum.setLemmaEmoji.isToggledOff) return;
InstructionsEnum.setLemmaEmoji.setToggledOff(true);
diff --git a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart
index 142a37753..aa22b6b3e 100644
--- a/lib/pangea/lemmas/lemma_highlight_emoji_row.dart
+++ b/lib/pangea/lemmas/lemma_highlight_emoji_row.dart
@@ -93,6 +93,7 @@ class LemmaHighlightEmojiRowState extends State
emoji,
"emoji-choice-item-$emoji-${widget.cId.lemma}",
);
+ showLemmaEmojiSnackbar(context, widget.cId, emoji);
} catch (e, s) {
debugger(when: kDebugMode);
ErrorHandler.logError(data: widget.cId.toJson(), e: e, s: s);
diff --git a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart
index 184844e8d..3e210bed1 100644
--- a/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart
+++ b/lib/pangea/toolbar/reading_assistance/select_mode_controller.dart
@@ -6,7 +6,10 @@ import 'package:flutter/foundation.dart';
import 'package:matrix/matrix.dart';
import 'package:path_provider/path_provider.dart';
+import 'package:fluffychat/pangea/analytics_misc/lemma_emoji_setter_mixin.dart';
import 'package:fluffychat/pangea/common/utils/async_state.dart';
+import 'package:fluffychat/pangea/common/utils/error_handler.dart';
+import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/speech_to_text/speech_to_text_response_model.dart';
import 'package:fluffychat/pangea/toolbar/message_practice/message_audio_card.dart';
@@ -71,7 +74,7 @@ class _AudioLoader extends AsyncLoader<(PangeaAudioFile, File?)> {
}
}
-class SelectModeController {
+class SelectModeController with LemmaEmojiSetter {
final PangeaMessageEvent messageEvent;
final _TranscriptionLoader _transcriptLoader;
final _TranslationLoader _translationLoader;
@@ -86,10 +89,14 @@ class SelectModeController {
_sttTranslationLoader = _STTTranslationLoader(messageEvent);
ValueNotifier selectedMode = ValueNotifier(null);
+ ValueNotifier<(ConstructIdentifier, String)?> constructEmojiNotifier =
+ ValueNotifier<(ConstructIdentifier, String)?>(null);
+
final StreamController contentChangedStream = StreamController.broadcast();
void dispose() {
selectedMode.dispose();
+ constructEmojiNotifier.dispose();
_transcriptLoader.dispose();
_translationLoader.dispose();
_sttTranslationLoader.dispose();
@@ -185,6 +192,27 @@ class SelectModeController {
selectedMode.value = mode;
}
+ Future setTokenEmoji(
+ ConstructIdentifier constructId,
+ String emoji,
+ String targetId,
+ ) async {
+ constructEmojiNotifier.value = (constructId, emoji);
+ try {
+ await setLemmaEmoji(
+ constructId,
+ emoji,
+ targetId,
+ );
+ } catch (e, s) {
+ ErrorHandler.logError(
+ data: constructId.toJson(),
+ e: e,
+ s: s,
+ );
+ }
+ }
+
Future fetchAudio() => _audioLoader.load();
Future fetchTranslation() => _translationLoader.load();
Future fetchTranscription() => _transcriptLoader.load();
diff --git a/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart b/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart
index 45bd36caf..9b1c31e98 100644
--- a/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart
+++ b/lib/pangea/toolbar/reading_assistance/token_emoji_button.dart
@@ -1,19 +1,16 @@
import 'package:flutter/material.dart';
-import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/analytics_misc/lemma_emoji_setter_mixin.dart';
-import 'package:fluffychat/pangea/common/utils/error_handler.dart';
-import 'package:fluffychat/pangea/common/utils/overlay.dart';
+import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
-import 'package:fluffychat/pangea/lemmas/lemma_meaning_builder.dart';
-import 'package:fluffychat/pangea/toolbar/reading_assistance/lemma_emoji_picker.dart';
import 'package:fluffychat/pangea/toolbar/reading_assistance/select_mode_buttons.dart';
import 'package:fluffychat/widgets/matrix.dart';
class TokenEmojiButton extends StatefulWidget {
final ValueNotifier selectModeNotifier;
- final ValueNotifier selectedTokenNotifier;
+ final ValueNotifier<(ConstructIdentifier, String)?> constructEmojiNotifier;
+ final VoidCallback onTap;
final PangeaToken? token;
final String? targetId;
@@ -22,7 +19,8 @@ class TokenEmojiButton extends StatefulWidget {
const TokenEmojiButton({
super.key,
required this.selectModeNotifier,
- required this.selectedTokenNotifier,
+ required this.constructEmojiNotifier,
+ required this.onTap,
this.token,
this.targetId,
this.enabled = true,
@@ -49,14 +47,14 @@ class TokenEmojiButtonState extends State
_initAnimation();
_prevMode = widget.selectModeNotifier.value;
widget.selectModeNotifier.addListener(_onUpdateSelectMode);
- widget.selectedTokenNotifier.addListener(_onSelectToken);
+ widget.constructEmojiNotifier.addListener(_onUpdateEmoji);
}
@override
void dispose() {
_controller?.dispose();
widget.selectModeNotifier.removeListener(_onUpdateSelectMode);
- widget.selectedTokenNotifier.removeListener(_onSelectToken);
+ widget.constructEmojiNotifier.removeListener(_onUpdateEmoji);
super.dispose();
}
@@ -87,68 +85,18 @@ class TokenEmojiButtonState extends State
_prevMode = mode;
}
- void _onSelectToken() {
- final selected = widget.selectedTokenNotifier.value;
- if (selected != null && selected == widget.token) {
- showTokenEmojiPopup();
+ void _onUpdateEmoji() {
+ final value = widget.constructEmojiNotifier.value;
+ if (value == null) return;
+
+ final constructId = value.$1;
+ final emoji = value.$2;
+
+ if (mounted && constructId == widget.token?.vocabConstructID) {
+ setState(() => _emoji = emoji);
}
}
- void showTokenEmojiPopup() {
- if (widget.targetId == null || widget.token == null) return;
- OverlayUtil.showPositionedCard(
- overlayKey: "overlay_emoji_selector",
- context: context,
- cardToShow: LemmaMeaningBuilder(
- langCode: MatrixState.pangeaController.userController.userL2Code!,
- constructId: widget.token!.vocabConstructID,
- builder: (context, controller) {
- return Material(
- type: MaterialType.transparency,
- child: Container(
- decoration: BoxDecoration(
- color: Theme.of(context).colorScheme.surface,
- borderRadius: BorderRadius.circular(
- AppConfig.borderRadius,
- ),
- ),
- child: LemmaEmojiPicker(
- emojis: controller.lemmaInfo?.emoji ?? [],
- onSelect: (emoji) {
- _setTokenEmoji(emoji);
- MatrixState.pAnyState.closeOverlay("overlay_emoji_selector");
- },
- loading: controller.isLoading,
- ),
- ),
- );
- },
- ),
- transformTargetId: widget.targetId!,
- closePrevOverlay: false,
- addBorder: false,
- maxWidth: (40 * 5) + (4 * 5) + 16,
- maxHeight: 60,
- );
- }
-
- void _setTokenEmoji(String emoji) {
- setState(() => _emoji = emoji);
-
- if (widget.targetId == null || widget.token == null) return;
- setLemmaEmoji(
- widget.token!.vocabConstructID,
- emoji,
- widget.targetId,
- ).catchError((e, s) {
- ErrorHandler.logError(
- data: widget.token!.toJson(),
- e: e,
- s: s,
- );
- });
- }
-
@override
Widget build(BuildContext context) {
if (_sizeAnimation == null) {
@@ -183,7 +131,7 @@ class TokenEmojiButtonState extends State
child: child,
builder: (context, child) {
return InkWell(
- onTap: showTokenEmojiPopup,
+ onTap: widget.onTap,
borderRadius: BorderRadius.circular(99.0),
child: Container(
height: _sizeAnimation!.value,
diff --git a/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart b/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart
index 00ba9ee27..e2892da8d 100644
--- a/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart
+++ b/lib/pangea/toolbar/word_card/lemma_reaction_picker.dart
@@ -11,16 +11,18 @@ import 'package:fluffychat/pangea/toolbar/reading_assistance/lemma_emoji_picker.
class LemmaReactionPicker extends StatelessWidget {
final Event? event;
final ConstructIdentifier construct;
+ final Future Function(String)? setEmoji;
final String langCode;
const LemmaReactionPicker({
super.key,
required this.construct,
+ required this.setEmoji,
required this.langCode,
this.event,
});
- Future setEmoji(
+ Future onSelect(
String emoji,
List emojis,
) async {
@@ -45,6 +47,8 @@ class LemmaReactionPicker extends StatelessWidget {
);
try {
+ await setEmoji?.call(emoji);
+
if (reactionEvent != null) {
await reactionEvent.redactEvent();
return;
@@ -97,7 +101,7 @@ class LemmaReactionPicker extends StatelessWidget {
return LemmaEmojiPicker(
emojis: controller.lemmaInfo?.emoji ?? [],
onSelect: event?.room.timeline != null
- ? (emoji) => setEmoji(
+ ? (emoji) => onSelect(
emoji,
controller.lemmaInfo?.emoji ?? [],
)
diff --git a/lib/pangea/toolbar/word_card/reading_assistance_content.dart b/lib/pangea/toolbar/word_card/reading_assistance_content.dart
index 71d2e0d97..486a92239 100644
--- a/lib/pangea/toolbar/word_card/reading_assistance_content.dart
+++ b/lib/pangea/toolbar/word_card/reading_assistance_content.dart
@@ -51,6 +51,11 @@ class ReadingAssistanceContent extends StatelessWidget {
onClose: () => overlayController.updateSelectedSpan(null),
langCode: overlayController.pangeaMessageEvent.messageDisplayLangCode,
onDismissNewWordOverlay: () => overlayController.setState(() {}),
+ setEmoji: (emoji) => overlayController.selectModeController.setTokenEmoji(
+ overlayController.selectedToken!.vocabConstructID,
+ emoji,
+ overlayController.tokenEmojiPopupKey(overlayController.selectedToken!),
+ ),
onFlagTokenInfo: (LemmaInfoResponse lemmaInfo, String phonetics) {
if (selectedTokenIndex < 0) return;
final requestData = TokenInfoFeedbackRequestData(
diff --git a/lib/pangea/toolbar/word_card/word_card_switcher.dart b/lib/pangea/toolbar/word_card/word_card_switcher.dart
index 1e2ab854f..18551a02a 100644
--- a/lib/pangea/toolbar/word_card/word_card_switcher.dart
+++ b/lib/pangea/toolbar/word_card/word_card_switcher.dart
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pangea/toolbar/layout/message_selection_positioner.dart';
-import 'package:fluffychat/pangea/toolbar/reading_assistance/select_mode_buttons.dart';
import 'package:fluffychat/pangea/toolbar/word_card/reading_assistance_content.dart';
class WordCardSwitcher extends StatelessWidget {
@@ -19,15 +18,13 @@ class WordCardSwitcher extends StatelessWidget {
? Alignment.bottomRight
: Alignment.bottomLeft,
duration: FluffyThemes.animationDuration,
- child: mode == SelectMode.emoji
- ? const SizedBox()
- : controller.widget.overlayController.selectedToken != null
- ? ReadingAssistanceContent(
- overlayController: controller.widget.overlayController,
- )
- : MessageReactionPicker(
- chatController: controller.widget.chatController,
- ),
+ child: controller.widget.overlayController.selectedToken != null
+ ? ReadingAssistanceContent(
+ overlayController: controller.widget.overlayController,
+ )
+ : MessageReactionPicker(
+ chatController: controller.widget.chatController,
+ ),
);
},
);
diff --git a/lib/pangea/toolbar/word_card/word_zoom_widget.dart b/lib/pangea/toolbar/word_card/word_zoom_widget.dart
index 3bb8b0bb9..2da2e272d 100644
--- a/lib/pangea/toolbar/word_card/word_zoom_widget.dart
+++ b/lib/pangea/toolbar/word_card/word_zoom_widget.dart
@@ -29,12 +29,14 @@ class WordZoomWidget extends StatelessWidget {
final VoidCallback? onDismissNewWordOverlay;
final Function(LemmaInfoResponse, String)? onFlagTokenInfo;
+ final Future Function(String)? setEmoji;
const WordZoomWidget({
super.key,
required this.token,
required this.construct,
required this.langCode,
+ this.setEmoji,
this.onClose,
this.wordIsNew = false,
this.event,
@@ -144,6 +146,7 @@ class WordZoomWidget extends StatelessWidget {
construct: construct,
langCode: langCode,
event: event,
+ setEmoji: setEmoji,
),
LemmaMeaningDisplay(
langCode: langCode,