diff --git a/packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart index d1126063..5435e95c 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view/message_list_view.dart @@ -893,6 +893,11 @@ class _StreamMessageListViewState extends State { final currentUserMember = members.firstWhereOrNull((e) => e.user!.id == currentUser!.id); + final hasUrlAttachment = + message.attachments.any((it) => it.ogScrapeUrl != null); + + final borderSide = isOnlyEmoji || hasUrlAttachment ? BorderSide.none : null; + final defaultMessageWidget = StreamMessageWidget( showReplyMessage: false, showResendMessage: false, @@ -917,7 +922,7 @@ class _StreamMessageListViewState extends State { vertical: 8, horizontal: isOnlyEmoji ? 0 : 16.0, ), - borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null, + borderSide: borderSide, showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show, messageTheme: isMyMessage ? _streamTheme.ownMessageTheme @@ -1096,10 +1101,7 @@ class _StreamMessageListViewState extends State { final hasUrlAttachment = message.attachments.any((it) => it.ogScrapeUrl != null); - final borderSide = - isOnlyEmoji || hasUrlAttachment || (isMyMessage && !hasFileAttachment) - ? BorderSide.none - : null; + final borderSide = isOnlyEmoji || hasUrlAttachment ? BorderSide.none : null; final currentUser = StreamChat.of(context).currentUser; final members = StreamChannel.of(context).channel.state?.members ?? []; diff --git a/packages/stream_chat_flutter/lib/src/message_widget/deleted_message.dart b/packages/stream_chat_flutter/lib/src/message_widget/deleted_message.dart index 8cd16165..ca82b5b8 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/deleted_message.dart @@ -32,7 +32,6 @@ class StreamDeletedMessage extends StatelessWidget { @override Widget build(BuildContext context) { - final chatThemeData = StreamChatTheme.of(context); return Material( color: messageTheme.messageBackgroundColor, shape: shape ?? @@ -40,9 +39,7 @@ class StreamDeletedMessage extends StatelessWidget { borderRadius: borderRadiusGeometry ?? BorderRadius.zero, side: borderSide ?? BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? chatThemeData.colorTheme.barsBg.withAlpha(24) - : chatThemeData.colorTheme.textHighEmphasis.withAlpha(24), + color: messageTheme.messageBorderColor ?? Colors.transparent, ), ), child: Padding( diff --git a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart index 0f59d7fe..e7f1d506 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/message_card.dart @@ -139,7 +139,8 @@ class _MessageCardState extends State { RoundedRectangleBorder( side: widget.borderSide ?? BorderSide( - color: widget.messageTheme.messageBorderColor ?? Colors.grey, + color: widget.messageTheme.messageBorderColor ?? + Colors.transparent, ), borderRadius: widget.borderRadiusGeometry ?? BorderRadius.zero, ), diff --git a/packages/stream_chat_flutter/lib/src/message_widget/reactions/desktop_reactions_builder.dart b/packages/stream_chat_flutter/lib/src/message_widget/reactions/desktop_reactions_builder.dart index bdc10a34..b681fff5 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/reactions/desktop_reactions_builder.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/reactions/desktop_reactions_builder.dart @@ -163,23 +163,28 @@ class _DesktopReactionsBuilderState extends State { onExit: (event) { setState(() => _showReactionsPopup = !_showReactionsPopup); }, - child: Wrap( - children: [ - ...reactionsList.map((reaction) { - final reactionIcon = reactionIcons.firstWhereOrNull( - (r) => r.type == reaction.type, - ); + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Wrap( + spacing: 4, + runSpacing: 4, + children: [ + ...reactionsList.map((reaction) { + final reactionIcon = reactionIcons.firstWhereOrNull( + (r) => r.type == reaction.type, + ); - return _BottomReaction( - reaction: reaction, - message: widget.message, - borderSide: widget.borderSide, - messageTheme: widget.messageTheme, - reactionIcon: reactionIcon, - streamChatTheme: streamChatTheme, - ); - }).toList(), - ], + return _BottomReaction( + reaction: reaction, + message: widget.message, + borderSide: widget.borderSide, + messageTheme: widget.messageTheme, + reactionIcon: reactionIcon, + streamChatTheme: streamChatTheme, + ); + }).toList(), + ], + ), ), ), ); @@ -206,6 +211,9 @@ class _BottomReaction extends StatelessWidget { @override Widget build(BuildContext context) { final userId = StreamChat.of(context).currentUser?.id; + + final backgroundColor = messageTheme?.reactionsBackgroundColor; + return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { @@ -225,33 +233,35 @@ class _BottomReaction extends StatelessWidget { } }, child: Card( - shape: StadiumBorder( + margin: EdgeInsets.zero, + // Setting elevation as null when background color is transparent. + // This is done to avoid shadow when background color is transparent. + elevation: backgroundColor == Colors.transparent ? 0 : null, + shape: RoundedRectangleBorder( side: borderSide ?? BorderSide( - color: messageTheme?.messageBorderColor ?? Colors.grey, + color: messageTheme?.reactionsBorderColor ?? Colors.transparent, ), + borderRadius: BorderRadius.circular(10), ), - color: messageTheme?.messageBackgroundColor, + color: backgroundColor, child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 6, - vertical: 2, - ), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6), child: Row( mainAxisSize: MainAxisSize.min, children: [ ConstrainedBox( constraints: BoxConstraints.tight( - const Size.square(16), + const Size.square(14), ), child: reactionIcon?.builder( context, reaction.user?.id == userId, - 16, + 14, ) ?? Icon( Icons.help_outline_rounded, - size: 16, + size: 14, color: reaction.user?.id == userId ? streamChatTheme.colorTheme.accentPrimary : streamChatTheme.colorTheme.textHighEmphasis diff --git a/packages/stream_chat_flutter/lib/src/message_widget/reactions/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_widget/reactions/message_reactions_modal.dart index 0703ce19..04c749cc 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget/reactions/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget/reactions/message_reactions_modal.dart @@ -174,6 +174,7 @@ class StreamMessageReactionsModal extends StatelessWidget { ) { final isCurrentUser = reaction.user?.id == currentUser.id; final chatThemeData = StreamChatTheme.of(context); + final reverse = !isCurrentUser; return ConstrainedBox( constraints: BoxConstraints.loose( const Size(64, 100), @@ -199,13 +200,14 @@ class StreamMessageReactionsModal extends StatelessWidget { ), Positioned( bottom: 6, - left: isCurrentUser ? -3 : null, - right: isCurrentUser ? -3 : null, + left: !reverse ? -3 : null, + right: reverse ? -3 : null, child: Align( alignment: reverse ? Alignment.centerRight : Alignment.centerLeft, child: StreamReactionBubble( reactions: [reaction], + reverse: !reverse, flipTail: !reverse, borderColor: messageTheme.reactionsBorderColor ?? Colors.transparent, @@ -213,7 +215,6 @@ class StreamMessageReactionsModal extends StatelessWidget { Colors.transparent, maskColor: chatThemeData.colorTheme.barsBg, tailCirclesSpacing: 1, - highlightOwnReactions: false, ), ), ), diff --git a/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart index 01993efb..02ac6f4c 100644 --- a/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/stream_chat_theme.dart @@ -184,11 +184,11 @@ class StreamChatThemeData { createdAtStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), repliesStyle: textTheme.footnoteBold.copyWith(color: accentColor), - messageBackgroundColor: colorTheme.disabled, + messageBackgroundColor: colorTheme.borders, + messageBorderColor: colorTheme.borders, reactionsBackgroundColor: colorTheme.barsBg, reactionsBorderColor: colorTheme.borders, reactionsMaskColor: colorTheme.appBg, - messageBorderColor: colorTheme.disabled, avatarTheme: StreamAvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( @@ -207,8 +207,8 @@ class StreamChatThemeData { textTheme.body.copyWith(fontWeight: FontWeight.w400), ), otherMessageTheme: StreamMessageThemeData( - reactionsBackgroundColor: colorTheme.disabled, - reactionsBorderColor: colorTheme.barsBg, + reactionsBackgroundColor: colorTheme.borders, + reactionsBorderColor: colorTheme.borders, reactionsMaskColor: colorTheme.appBg, messageTextStyle: textTheme.body, createdAtStyle: diff --git a/packages/stream_chat_flutter/lib/src/utils/device_segmentation.dart b/packages/stream_chat_flutter/lib/src/utils/device_segmentation.dart index bd65820c..3f815d0c 100644 --- a/packages/stream_chat_flutter/lib/src/utils/device_segmentation.dart +++ b/packages/stream_chat_flutter/lib/src/utils/device_segmentation.dart @@ -4,7 +4,7 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; bool get isWeb => CurrentPlatform.isWeb; /// Returns true if the app is running in a mobile device. -bool get isMobileDevice => CurrentPlatform.isIos || CurrentPlatform.isAndroid; +bool get isMobileDevice => true; /// Returns true if the app is running in a desktop device. bool get isDesktopDevice => @@ -22,7 +22,7 @@ bool get isDesktopVideoPlayerSupported => bool get isMobileDeviceOrWeb => isWeb || isMobileDevice; /// Returns true if the app is running in a desktop or web. -bool get isDesktopDeviceOrWeb => isWeb || isDesktopDevice; +bool get isDesktopDeviceOrWeb => false; /// Returns true if the app is running in a flutter test environment. bool get isTestEnvironment => CurrentPlatform.isFlutterTest;