show word card in image toolbar mode
This commit is contained in:
parent
60f572520d
commit
2897142b9d
9 changed files with 81 additions and 90 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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<T extends StatefulWidget> on State<T> {
|
||||
mixin LemmaEmojiSetter {
|
||||
Future<void> setLemmaEmoji(
|
||||
ConstructIdentifier constructId,
|
||||
String emoji,
|
||||
|
|
@ -26,11 +26,13 @@ mixin LemmaEmojiSetter<T extends StatefulWidget> on State<T> {
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ class LemmaHighlightEmojiRowState extends State<LemmaHighlightEmojiRow>
|
|||
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);
|
||||
|
|
|
|||
|
|
@ -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<SelectMode?> selectedMode = ValueNotifier<SelectMode?>(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<void> 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<void> fetchAudio() => _audioLoader.load();
|
||||
Future<void> fetchTranslation() => _translationLoader.load();
|
||||
Future<void> fetchTranscription() => _transcriptLoader.load();
|
||||
|
|
|
|||
|
|
@ -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<SelectMode?> selectModeNotifier;
|
||||
final ValueNotifier<PangeaToken?> 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<TokenEmojiButton>
|
|||
_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<TokenEmojiButton>
|
|||
_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<TokenEmojiButton>
|
|||
child: child,
|
||||
builder: (context, child) {
|
||||
return InkWell(
|
||||
onTap: showTokenEmojiPopup,
|
||||
onTap: widget.onTap,
|
||||
borderRadius: BorderRadius.circular(99.0),
|
||||
child: Container(
|
||||
height: _sizeAnimation!.value,
|
||||
|
|
|
|||
|
|
@ -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<void> Function(String)? setEmoji;
|
||||
final String langCode;
|
||||
|
||||
const LemmaReactionPicker({
|
||||
super.key,
|
||||
required this.construct,
|
||||
required this.setEmoji,
|
||||
required this.langCode,
|
||||
this.event,
|
||||
});
|
||||
|
||||
Future<void> setEmoji(
|
||||
Future<void> onSelect(
|
||||
String emoji,
|
||||
List<String> 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 ?? [],
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -29,12 +29,14 @@ class WordZoomWidget extends StatelessWidget {
|
|||
|
||||
final VoidCallback? onDismissNewWordOverlay;
|
||||
final Function(LemmaInfoResponse, String)? onFlagTokenInfo;
|
||||
final Future<void> 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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue