diff --git a/lib/config/app_config.dart b/lib/config/app_config.dart index bbeb5089f..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; @@ -37,8 +37,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/pages/chat/chat.dart b/lib/pages/chat/chat.dart index b45e21e36..22f4500a2 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1576,6 +1576,15 @@ 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 (timeline == null || + events.any( + (e) => e.aggregatedEvents(timeline!, RelationshipTypes.reaction).any( + (re) => re.content.tryGetMap('m.relates_to')?['key'] == emoji), + )) { + return; + } + for (final event in events) { await room.sendReaction( event.eventId, diff --git a/lib/pages/chat/events/message.dart b/lib/pages/chat/events/message.dart index 454660762..3d12fe24d 100644 --- a/lib/pages/chat/events/message.dart +++ b/lib/pages/chat/events/message.dart @@ -618,7 +618,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/lemmas/lemma_reaction_picker.dart b/lib/pangea/lemmas/lemma_reaction_picker.dart new file mode 100644 index 000000000..b229f2396 --- /dev/null +++ b/lib/pangea/lemmas/lemma_reaction_picker.dart @@ -0,0 +1,67 @@ +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'; + +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 = []; + 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); + }); + } + + 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, + 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 new file mode 100644 index 000000000..499970db1 --- /dev/null +++ b/lib/pangea/toolbar/reading_assistance_input_row/lemma_emoji_choice_item.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; + +import 'package:shimmer/shimmer.dart'; + +import 'package:fluffychat/config/app_config.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 + .withAlpha((0.4 * 255).toInt()); + } + + return Colors.transparent; + } + + @override + Widget build(BuildContext context) { + return Container( + height: 40, + width: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: color(context), + 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, + ), + ), + ); + } +} + +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/reading_assistance_input_row/reading_assistance_input_bar.dart b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart index bd1dda20a..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 @@ -4,7 +4,6 @@ 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'; 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'; @@ -27,7 +26,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; @@ -42,7 +42,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/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 8cd2d2ae9..02e4f38f3 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -7,15 +7,11 @@ 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/morphs/morph_features_enum.dart'; +import 'package:fluffychat/pangea/lemmas/lemma_reaction_picker.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'; class WordZoomWidget extends StatelessWidget { @@ -108,30 +104,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, ), @@ -158,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, + // ), + // ), + // ], + // ), ], ), ),