From 99fc3fd625f9e9bad8a4450b46fd11247a24b113 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 9 Oct 2024 09:57:25 -0400 Subject: [PATCH 1/2] Added message reactions widget to toolbar overlay --- .../chat/message_selection_overlay.dart | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index b44aad7f6..57f6bbcd9 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -4,6 +4,7 @@ import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/setting_keys.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; +import 'package:fluffychat/pages/chat/events/message_reactions.dart'; import 'package:fluffychat/pangea/enum/message_mode_enum.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; @@ -215,7 +216,17 @@ class MessageOverlayController extends State PangeaTokenText? get selectedSpan => _selectedSpan; - final int toolbarButtonsHeight = 50; + bool get hasReactions { + final reactionsEvents = widget._pangeaMessageEvent.event.aggregatedEvents( + widget.chatController.timeline!, + RelationshipTypes.reaction, + ); + return reactionsEvents.where((e) => !e.redacted).isNotEmpty; + } + + final double toolbarButtonsHeight = 50; + double get reactionsHeight => hasReactions ? 28 : 0; + double get belowMessageHeight => toolbarButtonsHeight + reactionsHeight; @override void didChangeDependencies() { @@ -230,7 +241,7 @@ class MessageOverlayController extends State final currentBottomOffset = screenHeight - messageOffset!.dy - messageSize!.height - - toolbarButtonsHeight; + belowMessageHeight; final bool hasHeaderOverflow = messageOffset!.dy < (AppConfig.toolbarMaxHeight + headerHeight); @@ -247,13 +258,12 @@ class MessageOverlayController extends State // check if shifting the overlay up could cause a header overflow final bottomOffsetDifference = footerHeight - currentBottomOffset; final newTopOffset = - messageOffset!.dy - bottomOffsetDifference - toolbarButtonsHeight; + messageOffset!.dy - bottomOffsetDifference - belowMessageHeight; final bool upshiftCausesHeaderOverflow = hasFooterOverflow && newTopOffset < (headerHeight + AppConfig.toolbarMaxHeight); if (hasHeaderOverflow || upshiftCausesHeaderOverflow) { - animationEndOffset = - midpoint - messageSize!.height - toolbarButtonsHeight; + animationEndOffset = midpoint - messageSize!.height - belowMessageHeight; final totalTopOffset = animationEndOffset + messageSize!.height + AppConfig.toolbarMaxHeight; final remainingSpace = screenHeight - totalTopOffset; @@ -270,12 +280,12 @@ class MessageOverlayController extends State // If, after ajusting the overlay position, the message still overflows the footer, // update the message height to fit the screen. The message is scrollable, so // this will make the both the toolbar box and the toolbar buttons visible. - if (animationEndOffset < footerHeight + toolbarButtonsHeight) { + if (animationEndOffset < footerHeight + belowMessageHeight) { final double remainingSpace = screenHeight - AppConfig.toolbarMaxHeight - headerHeight - footerHeight - - toolbarButtonsHeight; + belowMessageHeight; if (remainingSpace < messageSize!.height) { adjustedMessageHeight = remainingSpace; @@ -386,6 +396,17 @@ class MessageOverlayController extends State messageHeight: messageSize!.height, ), ), + if (hasReactions) + Padding( + padding: const EdgeInsets.all(4), + child: SizedBox( + height: reactionsHeight - 8, + child: MessageReactions( + widget._pangeaMessageEvent.event, + widget.chatController.timeline!, + ), + ), + ), ToolbarButtons( overlayController: this, width: 250, @@ -418,7 +439,7 @@ class MessageOverlayController extends State bottom: screenHeight - messageOffset!.dy - messageSize!.height - - toolbarButtonsHeight, + belowMessageHeight, child: overlayMessage, ) : AnimatedBuilder( From f125ed6fd818c93b4894b613e6d8839f8179e29c Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 9 Oct 2024 11:22:47 -0400 Subject: [PATCH 2/2] rebuild overlay on reaction event --- lib/pages/chat/chat.dart | 17 ++++++++++---- .../chat/message_selection_overlay.dart | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 2dd0ae476..c44796e47 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1251,7 +1251,14 @@ class ChatController extends State )) { return; } - return sendEmojiAction(emoji.emoji); + // #Pangea + // return sendEmojiAction(emoji.emoji); + sendEmojiAction(emoji.emoji); + + // don't need to clear these when sending while in select mode, + // but do need to clear these when reacting from the large emoji picker + setState(() => selectedEvents.clear()); + // Pangea# } void typeEmoji(Emoji? emoji) { @@ -1298,16 +1305,16 @@ class ChatController extends State void sendEmojiAction(String? emoji) async { final events = List.from(selectedEvents); - setState(() => selectedEvents.clear()); + // #Pangea + // keep this event selected in case the user wants to send another emoji + // setState(() => selectedEvents.clear()); + // Pangea# for (final event in events) { await room.sendReaction( event.eventId, emoji!, ); } - // #Pangea - clearSelectedEvents(); - // Pangea# } // #Pangea diff --git a/lib/pangea/widgets/chat/message_selection_overlay.dart b/lib/pangea/widgets/chat/message_selection_overlay.dart index 57f6bbcd9..428d36e79 100644 --- a/lib/pangea/widgets/chat/message_selection_overlay.dart +++ b/lib/pangea/widgets/chat/message_selection_overlay.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:developer'; import 'package:fluffychat/config/app_config.dart'; @@ -49,6 +50,7 @@ class MessageSelectionOverlay extends StatefulWidget { class MessageOverlayController extends State with SingleTickerProviderStateMixin { late AnimationController _animationController; + StreamSubscription? _reactionSubscription; Animation? _overlayPositionAnimation; MessageMode toolbarMode = MessageMode.translation; @@ -73,6 +75,26 @@ class MessageOverlayController extends State activitiesLeftToComplete = activitiesLeftToComplete - widget._pangeaMessageEvent.numberOfActivitiesCompleted; + _reactionSubscription = + widget.chatController.room.client.onSync.stream.where( + (update) { + // check if this sync update has a reaction event or a + // redaction (of a reaction event). If so, rebuild the overlay + final room = widget.chatController.room; + final timelineEvents = update.rooms?.join?[room.id]?.timeline?.events; + if (timelineEvents == null) return false; + + final eventID = widget._pangeaMessageEvent.event.eventId; + return timelineEvents.any( + (e) => + e.type == EventTypes.Redaction || + (e.type == EventTypes.Reaction && + Event.fromMatrixEvent(e, room).relationshipEventId == + eventID), + ); + }, + ).listen((_) => setState(() {})); + setInitialToolbarMode(); } @@ -315,6 +337,7 @@ class MessageOverlayController extends State @override void dispose() { _animationController.dispose(); + _reactionSubscription?.cancel(); super.dispose(); }