From fc98b90736e5b74a7bc181619b192ff812a6c98d Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Fri, 6 Jun 2025 17:42:47 -0400 Subject: [PATCH 1/7] feat: allow sending of lemma emojis as reactions, remove emoji picker to simplify selected view --- lib/config/app_config.dart | 6 +- lib/pages/chat/chat.dart | 26 ++++---- lib/pages/chat/events/message.dart | 18 +++-- lib/pangea/chat/widgets/chat_input_bar.dart | 3 +- lib/pangea/lemmas/lemma_reaction_picker.dart | 65 +++++++++++++++++++ .../lemma_emoji_choice_item.dart | 53 +++++++++++++++ .../overlay_footer.dart | 3 +- .../reading_assistance_input_bar.dart | 9 ++- .../widgets/message_selection_positioner.dart | 16 ++--- .../widgets/word_zoom/word_zoom_widget.dart | 56 ++++++++-------- 10 files changed, 187 insertions(+), 68 deletions(-) create mode 100644 lib/pangea/lemmas/lemma_reaction_picker.dart create mode 100644 lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index d04d20be0..f72f1438c 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -1,8 +1,6 @@ -import 'package:flutter/material.dart'; - -import 'package:matrix/matrix.dart'; - import 'package:fluffychat/pangea/common/config/environment.dart'; +import 'package:flutter/material.dart'; +import 'package:matrix/matrix.dart'; abstract class AppConfig { // #Pangea diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 7ee0881e0..ec5e8da48 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -4,22 +4,9 @@ import 'dart:async'; import 'dart:developer'; import 'dart:io'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; - import 'package:collection/collection.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:go_router/go_router.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:matrix/matrix.dart'; -import 'package:scroll_to_index/scroll_to_index.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:universal_html/html.dart' as html; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; @@ -66,6 +53,18 @@ import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart' import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/share_scaffold_dialog.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:go_router/go_router.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:matrix/matrix.dart'; +import 'package:scroll_to_index/scroll_to_index.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; + import '../../utils/account_bundles.dart'; import '../../utils/localized_exception_extension.dart'; import 'send_file_dialog.dart'; @@ -1542,6 +1541,7 @@ class ChatController extends State // setState(() => selectedEvents.clear()); // Pangea# for (final event in events) { + // if reaction already exists, don't send it again await room.sendReaction( event.eventId, emoji!, diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 6d923c7b3..366b87f12 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -1,11 +1,5 @@ import 'dart:ui' as ui; -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix/matrix.dart'; -import 'package:swipe_to_action/swipe_to_action.dart'; - import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart'; @@ -17,6 +11,11 @@ import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:matrix/matrix.dart'; +import 'package:swipe_to_action/swipe_to_action.dart'; + import '../../../config/app_config.dart'; import 'message_content.dart'; import 'message_reactions.dart'; @@ -614,7 +613,12 @@ class Message extends StatelessWidget { crossAxisAlignment: ownMessage ? CrossAxisAlignment.end : CrossAxisAlignment.start, children: [ - if (displayTime || selected) + // #Pangea + if (displayTime) + // we don't need to display the time if the message is selected + // we have the background blotted out so you can't see the time anyway + // if (displayTime || selected) + // Pangea# Padding( padding: displayTime ? const EdgeInsets.symmetric(vertical: 8.0) diff --git a/lib/pangea/chat/widgets/chat_input_bar.dart b/lib/pangea/chat/widgets/chat_input_bar.dart index 37fb3d397..bad1545b1 100644 --- a/lib/pangea/chat/widgets/chat_input_bar.dart +++ b/lib/pangea/chat/widgets/chat_input_bar.dart @@ -1,13 +1,12 @@ import 'dart:async'; -import 'package:flutter/material.dart'; - import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/chat_emoji_picker.dart'; import 'package:fluffychat/pages/chat/reply_display.dart'; import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart'; import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart'; +import 'package:flutter/material.dart'; class ChatInputBar extends StatefulWidget { final ChatController controller; diff --git a/lib/pangea/lemmas/lemma_reaction_picker.dart b/lib/pangea/lemmas/lemma_reaction_picker.dart new file mode 100644 index 000000000..4c30ce02d --- /dev/null +++ b/lib/pangea/lemmas/lemma_reaction_picker.dart @@ -0,0 +1,65 @@ +import 'package:fluffychat/pages/chat/chat.dart'; +import 'package:fluffychat/pangea/common/utils/error_handler.dart'; +import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; +import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart'; +import 'package:flutter/material.dart'; + +class LemmaReactionPicker extends StatefulWidget { + final ConstructIdentifier cId; + final ChatController controller; + final double? iconSize; + + const LemmaReactionPicker({ + super.key, + required this.cId, + required this.controller, + this.iconSize, + }); + + @override + LemmaReactionPickerState createState() => LemmaReactionPickerState(); +} + +class LemmaReactionPickerState extends State { + List displayEmoji = []; + + @override + void initState() { + super.initState(); + widget.cId.getLemmaInfo().then((info) { + setState(() => displayEmoji = info.emoji); + }).catchError((e, s) { + ErrorHandler.logError(data: widget.cId.toJson(), e: e, s: s); + }); + } + + // @override + // didUpdateWidget(LemmaReactionPicker oldWidget) { + // if (oldWidget.isSelected != widget.isSelected || + // widget.cId.userSetEmoji != oldWidget.cId.userSetEmoji) { + // setState(() => displayEmoji = widget.cId.userSetEmoji.firstOrNull); + // } + // super.didUpdateWidget(oldWidget); + // } + + void setEmoji(String emoji) => widget.controller.sendEmojiAction(emoji); + + @override + Widget build(BuildContext context) { + return Container( + height: 50, + alignment: Alignment.center, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: displayEmoji + .map( + (emoji) => LemmaEmojiChoiceItem( + content: emoji, + onTap: () => setEmoji(emoji), + ), + ) + .toList(), + ), + ); + } +} diff --git a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart new file mode 100644 index 000000000..0f73636a4 --- /dev/null +++ b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart @@ -0,0 +1,53 @@ +import 'package:fluffychat/config/app_config.dart'; +import 'package:flutter/material.dart'; + +class LemmaEmojiChoiceItem extends StatefulWidget { + const LemmaEmojiChoiceItem({ + super.key, + required this.content, + required this.onTap, + }); + + final String content; + final Function onTap; + + @override + LemmaEmojiChoiceItemState createState() => LemmaEmojiChoiceItemState(); +} + +class LemmaEmojiChoiceItemState extends State { + bool _isHovered = false; + + Color color(BuildContext context) { + if (_isHovered) { + return Theme.of(context).colorScheme.primaryContainer; + } + + return Colors.transparent; + } + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: color(context).withAlpha((0.4 * 255).toInt()), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + ), + child: InkWell( + onHover: (isHovered) => setState(() => _isHovered = isHovered), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + onTap: () { + if (!mounted) { + return; + } + widget.onTap(); + }, + child: Text( + widget.content, + style: Theme.of(context).textTheme.headlineSmall, + ), + ), + ); + } +} diff --git a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart index 8f7b0ec62..c476b3211 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart @@ -1,5 +1,3 @@ -import 'package:flutter/material.dart'; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; @@ -7,6 +5,7 @@ import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart'; import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; import 'package:fluffychat/pangea/toolbar/widgets/practice_mode_buttons.dart'; +import 'package:flutter/material.dart'; class OverlayFooter extends StatelessWidget { final ChatController controller; diff --git a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart index bd1dda20a..a47978d95 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart @@ -1,7 +1,3 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/reactions_picker.dart'; @@ -11,6 +7,8 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_mode_locked_card.dart' import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_translation_card.dart'; import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; const double minContentHeight = 120; @@ -27,7 +25,8 @@ class ReadingAssistanceInputBar extends StatelessWidget { Widget barContent(BuildContext context) { if (overlayController.readingAssistanceMode != ReadingAssistanceMode.practiceMode) { - return ReactionsPicker(controller); + return const SizedBox(); + // return ReactionsPicker(controller); } Widget? content; diff --git a/lib/pangea/toolbar/widgets/message_selection_positioner.dart b/lib/pangea/toolbar/widgets/message_selection_positioner.dart index ce7c2bea8..76d7b908c 100644 --- a/lib/pangea/toolbar/widgets/message_selection_positioner.dart +++ b/lib/pangea/toolbar/widgets/message_selection_positioner.dart @@ -1,10 +1,6 @@ import 'dart:async'; import 'dart:math'; -import 'package:flutter/material.dart'; - -import 'package:matrix/matrix.dart'; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; @@ -24,6 +20,8 @@ import 'package:fluffychat/pangea/toolbar/widgets/overlay_header.dart'; import 'package:fluffychat/pangea/toolbar/widgets/select_mode_buttons.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/material.dart'; +import 'package:matrix/matrix.dart'; /// Controls positioning of the message overlay. class MessageSelectionPositioner extends StatefulWidget { @@ -149,10 +147,11 @@ class MessageSelectionPositionerState extends State _centeredMessageOffset = Offset( offset.dx - _columnWidth - _horizontalPadding - 2.0, _mediaQuery!.size.height - - (offset.dy - - ((AppConfig.practiceModeInputBarHeight - - AppConfig.selectModeInputBarHeight) * - 0.75)) - + offset.dy - + // (offset.dy - + // ((AppConfig.practiceModeInputBarHeight - + // AppConfig.selectModeInputBarHeight) * + // 0.75)) - renderBox.size.height - _reactionsHeight, ); @@ -485,6 +484,7 @@ class MessageSelectionPositionerState extends State } double get _footerHeight { + return 0; return _inputBarSize + (_mediaQuery?.padding.bottom ?? 0); } diff --git a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 8cd2d2ae9..12007cf71 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -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'; @@ -7,16 +5,16 @@ import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dar import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart'; -import 'package:fluffychat/pangea/lemmas/lemma_emoji_row.dart'; +import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.dart'; import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; -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_audio_button.dart'; import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart'; 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; @@ -108,30 +106,34 @@ class WordZoomWidget extends StatelessWidget { const SizedBox( height: 8.0, ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - constraints: const BoxConstraints( - minHeight: 40, - ), - alignment: Alignment.center, - child: LemmaEmojiRow( - cId: _selectedToken.vocabConstructID, - onTapOverride: overlayController.hideWordCardContent && - hasEmojiActivity - ? () => overlayController.updateToolbarMode( - MessageMode.wordEmoji, - ) - : null, - isSelected: - overlayController.toolbarMode == MessageMode.wordEmoji, - emojiSetCallback: () => overlayController.setState(() {}), - shouldShowEmojis: !hasEmojiActivity, - ), - ), - ], + LemmaReactionPicker( + cId: _selectedToken.vocabConstructID, + controller: overlayController.widget.chatController, ), + // Row( + // mainAxisAlignment: MainAxisAlignment.center, + // children: [ + // Container( + // constraints: const BoxConstraints( + // minHeight: 40, + // ), + // alignment: Alignment.center, + // child: LemmaEmojiRow( + // cId: _selectedToken.vocabConstructID, + // onTapOverride: overlayController.hideWordCardContent && + // hasEmojiActivity + // ? () => overlayController.updateToolbarMode( + // MessageMode.wordEmoji, + // ) + // : null, + // isSelected: + // overlayController.toolbarMode == MessageMode.wordEmoji, + // emojiSetCallback: () => overlayController.setState(() {}), + // shouldShowEmojis: !hasEmojiActivity, + // ), + // ), + // ], + // ), const SizedBox( height: 8.0, ), From 0a5f77e4131deec0cf47b904bdb433b054548ff6 Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Mon, 9 Jun 2025 13:48:14 -0400 Subject: [PATCH 2/7] don't send the same reaction twice --- lib/pages/chat/chat.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index ec5e8da48..60a6ec49d 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1540,8 +1540,14 @@ class ChatController extends State // keep this event selected in case the user wants to send another emoji // setState(() => selectedEvents.clear()); // Pangea# + // if reaction already exists, don't send it again + if (_allReactionEvents.any( + (e) => e.content.tryGetMap('m.relates_to')?['key'] == emoji, + )) { + return; + } + for (final event in events) { - // if reaction already exists, don't send it again await room.sendReaction( event.eventId, emoji!, From 1f001eb1449e3f208cd5e45f62dad8f6d98359f5 Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Mon, 9 Jun 2025 16:37:34 -0400 Subject: [PATCH 3/7] feat(reactions): dont double send reaction --- lib/pages/chat/chat.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 60a6ec49d..dab1050b4 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1541,9 +1541,11 @@ class ChatController extends State // setState(() => selectedEvents.clear()); // Pangea# // if reaction already exists, don't send it again - if (_allReactionEvents.any( - (e) => e.content.tryGetMap('m.relates_to')?['key'] == emoji, - )) { + if (timeline == null || + events.any( + (e) => e.aggregatedEvents(timeline!, RelationshipTypes.reaction).any( + (re) => re.content.tryGetMap('m.relates_to')?['key'] == emoji), + )) { return; } From fc2a6cfb623dfff180b633a27224215f83525fdf Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Mon, 9 Jun 2025 17:03:56 -0400 Subject: [PATCH 4/7] clean up implementation of positioning to avoid problems --- lib/config/app_config.dart | 4 ++-- .../reading_assistance_input_bar.dart | 4 ++-- .../toolbar/widgets/message_selection_positioner.dart | 10 ++++------ 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 168fc6172..644ec3da8 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -35,8 +35,8 @@ abstract class AppConfig { static const double readingAssistanceInputBarHeight = 140.0; static const double reactionsPickerHeight = 48.0; static const double chatInputRowOverlayPadding = 8.0; - static const double selectModeInputBarHeight = - reactionsPickerHeight + (chatInputRowOverlayPadding * 2) + toolbarSpacing; + static const double selectModeInputBarHeight = 0; + // reactionsPickerHeight + (chatInputRowOverlayPadding * 2) + toolbarSpacing; static const double practiceModeInputBarHeight = readingAssistanceInputBarHeight + toolbarButtonsHeight + diff --git a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart index a47978d95..d7fc2e88c 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart @@ -1,6 +1,5 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/chat.dart'; -import 'package:fluffychat/pages/chat/reactions_picker.dart'; import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_mode_locked_card.dart'; @@ -41,7 +40,8 @@ class ReadingAssistanceInputBar extends StatelessWidget { : null; if (overlayController.pangeaMessageEvent?.isAudioMessage == true) { - return ReactionsPicker(controller); + return const SizedBox(); + // return ReactionsPicker(controller); } else { switch (overlayController.toolbarMode) { case MessageMode.messageSpeechToText: diff --git a/lib/pangea/toolbar/widgets/message_selection_positioner.dart b/lib/pangea/toolbar/widgets/message_selection_positioner.dart index b60f07756..b4566d697 100644 --- a/lib/pangea/toolbar/widgets/message_selection_positioner.dart +++ b/lib/pangea/toolbar/widgets/message_selection_positioner.dart @@ -147,11 +147,10 @@ class MessageSelectionPositionerState extends State _centeredMessageOffset = Offset( offset.dx - _columnWidth - _horizontalPadding - 2.0, _mediaQuery!.size.height - - offset.dy - - // (offset.dy - - // ((AppConfig.practiceModeInputBarHeight - - // AppConfig.selectModeInputBarHeight) * - // 0.75)) - + (offset.dy - + ((AppConfig.practiceModeInputBarHeight - + AppConfig.selectModeInputBarHeight) * + 0.75)) - renderBox.size.height - _reactionsHeight, ); @@ -484,7 +483,6 @@ class MessageSelectionPositionerState extends State } double get _footerHeight { - return 0; return _inputBarSize + (_mediaQuery?.padding.bottom ?? 0); } From cc015c930d03628f696a99539807764635bb45bd Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 9 Jun 2025 17:11:04 -0400 Subject: [PATCH 5/7] chore: formatting --- lib/config/app_config.dart | 4 ++- lib/pages/chat/chat.dart | 25 ++++++++++--------- lib/pages/chat/events/message.dart | 11 ++++---- lib/pangea/chat/widgets/chat_input_bar.dart | 3 ++- lib/pangea/lemmas/lemma_reaction_picker.dart | 3 ++- .../lemma_emoji_choice_item.dart | 3 ++- .../overlay_footer.dart | 3 ++- .../reading_assistance_input_bar.dart | 6 +++-- .../widgets/message_selection_positioner.dart | 6 +++-- .../widgets/word_zoom/word_zoom_widget.dart | 3 ++- 10 files changed, 40 insertions(+), 27 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 644ec3da8..5041c776e 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -1,7 +1,9 @@ -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'; diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 8a6b44580..22f4500a2 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -5,9 +5,22 @@ import 'dart:developer'; import 'dart:io'; import 'dart:math'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + import 'package:collection/collection.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:go_router/go_router.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:matrix/matrix.dart'; +import 'package:scroll_to_index/scroll_to_index.dart'; +import 'package:sentry_flutter/sentry_flutter.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:universal_html/html.dart' as html; + import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; @@ -55,18 +68,6 @@ import 'package:fluffychat/widgets/adaptive_dialogs/show_text_input_dialog.dart' import 'package:fluffychat/widgets/future_loading_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/share_scaffold_dialog.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:go_router/go_router.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:matrix/matrix.dart'; -import 'package:scroll_to_index/scroll_to_index.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:shared_preferences/shared_preferences.dart'; -import 'package:universal_html/html.dart' as html; - import '../../utils/account_bundles.dart'; import '../../utils/localized_exception_extension.dart'; import 'send_file_dialog.dart'; diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 940c80b16..3d12fe24d 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -1,5 +1,11 @@ import 'dart:ui' as ui; +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:matrix/matrix.dart'; +import 'package:swipe_to_action/swipe_to_action.dart'; + import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/events/room_creation_state_event.dart'; @@ -11,11 +17,6 @@ import 'package:fluffychat/utils/string_color.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:fluffychat/widgets/member_actions_popup_menu_button.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix/matrix.dart'; -import 'package:swipe_to_action/swipe_to_action.dart'; - import '../../../config/app_config.dart'; import 'message_content.dart'; import 'message_reactions.dart'; diff --git a/lib/pangea/chat/widgets/chat_input_bar.dart b/lib/pangea/chat/widgets/chat_input_bar.dart index f824549dd..6b7afb825 100644 --- a/lib/pangea/chat/widgets/chat_input_bar.dart +++ b/lib/pangea/chat/widgets/chat_input_bar.dart @@ -1,12 +1,13 @@ import 'dart:async'; +import 'package:flutter/material.dart'; + import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pages/chat/chat_emoji_picker.dart'; import 'package:fluffychat/pages/chat/reply_display.dart'; import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart'; import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart'; -import 'package:flutter/material.dart'; class ChatInputBar extends StatefulWidget { final ChatController controller; diff --git a/lib/pangea/lemmas/lemma_reaction_picker.dart b/lib/pangea/lemmas/lemma_reaction_picker.dart index 4c30ce02d..3cba97dad 100644 --- a/lib/pangea/lemmas/lemma_reaction_picker.dart +++ b/lib/pangea/lemmas/lemma_reaction_picker.dart @@ -1,8 +1,9 @@ +import 'package:flutter/material.dart'; + import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart'; -import 'package:flutter/material.dart'; class LemmaReactionPicker extends StatefulWidget { final ConstructIdentifier cId; diff --git a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart index 0f73636a4..a8cff39c7 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart @@ -1,6 +1,7 @@ -import 'package:fluffychat/config/app_config.dart'; import 'package:flutter/material.dart'; +import 'package:fluffychat/config/app_config.dart'; + class LemmaEmojiChoiceItem extends StatefulWidget { const LemmaEmojiChoiceItem({ super.key, diff --git a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart index c476b3211..8f7b0ec62 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/overlay_footer.dart @@ -1,3 +1,5 @@ +import 'package:flutter/material.dart'; + import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; @@ -5,7 +7,6 @@ import 'package:fluffychat/pangea/chat/widgets/pangea_chat_input_row.dart'; import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; import 'package:fluffychat/pangea/toolbar/widgets/practice_mode_buttons.dart'; -import 'package:flutter/material.dart'; class OverlayFooter extends StatelessWidget { final ChatController controller; diff --git a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart index d7fc2e88c..a831f2dcd 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart @@ -1,3 +1,7 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_gen/gen_l10n/l10n.dart'; + import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/chat.dart'; import 'package:fluffychat/pangea/toolbar/enums/message_mode_enum.dart'; @@ -6,8 +10,6 @@ import 'package:fluffychat/pangea/toolbar/widgets/message_mode_locked_card.dart' import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_translation_card.dart'; import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; const double minContentHeight = 120; diff --git a/lib/pangea/toolbar/widgets/message_selection_positioner.dart b/lib/pangea/toolbar/widgets/message_selection_positioner.dart index b4566d697..53a8436ac 100644 --- a/lib/pangea/toolbar/widgets/message_selection_positioner.dart +++ b/lib/pangea/toolbar/widgets/message_selection_positioner.dart @@ -1,6 +1,10 @@ import 'dart:async'; import 'dart:math'; +import 'package:flutter/material.dart'; + +import 'package:matrix/matrix.dart'; + import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; @@ -20,8 +24,6 @@ import 'package:fluffychat/pangea/toolbar/widgets/overlay_header.dart'; import 'package:fluffychat/pangea/toolbar/widgets/select_mode_buttons.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; -import 'package:flutter/material.dart'; -import 'package:matrix/matrix.dart'; /// Controls positioning of the message overlay. class MessageSelectionPositioner extends StatefulWidget { diff --git a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 12007cf71..000a0cbdf 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -1,3 +1,5 @@ +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'; @@ -14,7 +16,6 @@ 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; From 0e7727dc4184733dde06fe3385a3b6fddad9da6b Mon Sep 17 00:00:00 2001 From: wcjord <32568597+wcjord@users.noreply.github.com> Date: Tue, 10 Jun 2025 10:20:59 -0400 Subject: [PATCH 6/7] loading indicator for emojis and... hiding of grammar icons --- lib/config/app_config.dart | 2 +- lib/pangea/lemmas/lemma_reaction_picker.dart | 35 ++++----- .../lemma_emoji_choice_item.dart | 39 +++++++++- .../widgets/word_zoom/word_zoom_widget.dart | 73 +++++++++---------- 4 files changed, 90 insertions(+), 59 deletions(-) diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index 5041c776e..e6a8eeed0 100644 --- a/lib/config/app_config.dart +++ b/lib/config/app_config.dart @@ -28,7 +28,7 @@ abstract class AppConfig { static const bool enableRegistration = true; // #Pangea static const double toolbarMaxHeight = 250.0; - static const double toolbarMinHeight = 200.0; + static const double toolbarMinHeight = 150.0; static const double toolbarMinWidth = 350.0; static const double defaultHeaderHeight = 56.0; static const double toolbarButtonsHeight = 50.0; diff --git a/lib/pangea/lemmas/lemma_reaction_picker.dart b/lib/pangea/lemmas/lemma_reaction_picker.dart index 3cba97dad..b229f2396 100644 --- a/lib/pangea/lemmas/lemma_reaction_picker.dart +++ b/lib/pangea/lemmas/lemma_reaction_picker.dart @@ -23,26 +23,20 @@ class LemmaReactionPicker extends StatefulWidget { class LemmaReactionPickerState extends State { List displayEmoji = []; + bool loading = true; @override void initState() { super.initState(); widget.cId.getLemmaInfo().then((info) { + loading = false; setState(() => displayEmoji = info.emoji); }).catchError((e, s) { ErrorHandler.logError(data: widget.cId.toJson(), e: e, s: s); + setState(() => loading = false); }); } - // @override - // didUpdateWidget(LemmaReactionPicker oldWidget) { - // if (oldWidget.isSelected != widget.isSelected || - // widget.cId.userSetEmoji != oldWidget.cId.userSetEmoji) { - // setState(() => displayEmoji = widget.cId.userSetEmoji.firstOrNull); - // } - // super.didUpdateWidget(oldWidget); - // } - void setEmoji(String emoji) => widget.controller.sendEmojiAction(emoji); @override @@ -52,14 +46,21 @@ class LemmaReactionPickerState extends State { alignment: Alignment.center, child: Row( mainAxisAlignment: MainAxisAlignment.center, - children: displayEmoji - .map( - (emoji) => LemmaEmojiChoiceItem( - content: emoji, - onTap: () => setEmoji(emoji), - ), - ) - .toList(), + spacing: 4.0, + children: loading == false + ? displayEmoji + .map( + (emoji) => LemmaEmojiChoiceItem( + content: emoji, + onTap: () => setEmoji(emoji), + ), + ) + .toList() + : [1, 2, 3, 4, 5] + .map( + (e) => const LemmaEmojiChoicePlaceholder(), + ) + .toList(), ), ); } diff --git a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart index a8cff39c7..bc83b54b7 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:shimmer/shimmer.dart'; import 'package:fluffychat/config/app_config.dart'; @@ -21,7 +22,10 @@ class LemmaEmojiChoiceItemState extends State { Color color(BuildContext context) { if (_isHovered) { - return Theme.of(context).colorScheme.primaryContainer; + return Theme.of(context) + .colorScheme + .primaryContainer + .withAlpha((0.4 * 255).toInt()); } return Colors.transparent; @@ -30,9 +34,11 @@ class LemmaEmojiChoiceItemState extends State { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.all(8), + height: 40, + width: 40, + alignment: Alignment.center, decoration: BoxDecoration( - color: color(context).withAlpha((0.4 * 255).toInt()), + color: color(context), borderRadius: BorderRadius.circular(AppConfig.borderRadius), ), child: InkWell( @@ -52,3 +58,30 @@ class LemmaEmojiChoiceItemState extends State { ); } } + +class LemmaEmojiChoicePlaceholder extends StatelessWidget { + const LemmaEmojiChoicePlaceholder({ + super.key, + this.size = 40, + }); + + final double size; + + @override + Widget build(BuildContext context) { + return Shimmer.fromColors( + baseColor: Colors.transparent, + highlightColor: + Theme.of(context).colorScheme.primaryContainer.withAlpha(0xAA), + child: Container( + height: size, + width: size, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.primaryContainer.withAlpha(0x66), + borderRadius: BorderRadius.circular(AppConfig.borderRadius), + ), + ), + ); + } +} diff --git a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 000a0cbdf..02e4f38f3 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -8,13 +8,10 @@ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; import 'package:fluffychat/pangea/lemmas/construct_xp_widget.dart'; import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.dart'; -import 'package:fluffychat/pangea/morphs/morph_features_enum.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart'; -import 'package:fluffychat/pangea/toolbar/widgets/practice_activity/word_audio_button.dart'; import 'package:fluffychat/pangea/toolbar/widgets/word_zoom/lemma_meaning_widget.dart'; 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'; class WordZoomWidget extends StatelessWidget { @@ -161,41 +158,41 @@ class WordZoomWidget extends StatelessWidget { ], ), ), - const SizedBox( - height: 8.0, - ), - Wrap( - alignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 8.0, - children: [ - if (token.text.content.toLowerCase() != - token.lemma.text.toLowerCase()) ...[ - Text( - _selectedToken.text.content, - style: Theme.of(context).textTheme.bodyLarge, - overflow: TextOverflow.ellipsis, - ), - WordAudioButton( - text: _selectedToken.text.content, - baseOpacity: 0.4, - uniqueID: "word-zoom-audio-${_selectedToken.text.content}", - langCode: overlayController - .pangeaMessageEvent!.messageDisplayLangCode, - ), - ], - ..._selectedToken.morphsBasicallyEligibleForPracticeByPriority - .map( - (cId) => MorphologicalListItem( - morphFeature: MorphFeaturesEnumExtension.fromString( - cId.category, - ), - token: _selectedToken, - overlayController: overlayController, - ), - ), - ], - ), + // const SizedBox( + // height: 8.0, + // ), + // Wrap( + // alignment: WrapAlignment.center, + // crossAxisAlignment: WrapCrossAlignment.center, + // spacing: 8.0, + // children: [ + // if (token.text.content.toLowerCase() != + // token.lemma.text.toLowerCase()) ...[ + // Text( + // _selectedToken.text.content, + // style: Theme.of(context).textTheme.bodyLarge, + // overflow: TextOverflow.ellipsis, + // ), + // WordAudioButton( + // text: _selectedToken.text.content, + // baseOpacity: 0.4, + // uniqueID: "word-zoom-audio-${_selectedToken.text.content}", + // langCode: overlayController + // .pangeaMessageEvent!.messageDisplayLangCode, + // ), + // ], + // ..._selectedToken.morphsBasicallyEligibleForPracticeByPriority + // .map( + // (cId) => MorphologicalListItem( + // morphFeature: MorphFeaturesEnumExtension.fromString( + // cId.category, + // ), + // token: _selectedToken, + // overlayController: overlayController, + // ), + // ), + // ], + // ), ], ), ), From fe708f66a4b63d576191402b84933b7acaf5fb4b Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 10 Jun 2025 11:19:07 -0400 Subject: [PATCH 7/7] chore: formatting --- .../reading_assistance_input_row/lemma_emoji_choice_item.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart index bc83b54b7..499970db1 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; + import 'package:shimmer/shimmer.dart'; import 'package:fluffychat/config/app_config.dart';