From 4fb41bf601763de9d7c98009a044d48bf956147d Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:02:46 +0200 Subject: [PATCH 01/15] fix message radius and reaction padding --- lib/src/message_widget.dart | 6 +++--- lib/src/reaction_bubble.dart | 1 + lib/src/reaction_picker.dart | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 967fb72b..10298436 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -498,8 +498,8 @@ class _MessageWidgetState extends State { }); } - ContinuousRectangleBorder _getDefaultShape(BuildContext context) { - return ContinuousRectangleBorder( + ShapeBorder _getDefaultShape(BuildContext context) { + return RoundedRectangleBorder( side: widget.attachmentBorderSide ?? widget.borderSide ?? BorderSide( @@ -718,7 +718,7 @@ class _MessageWidgetState extends State { onLongPress: () => onLongPress(context), child: Material( shape: widget.shape ?? - ContinuousRectangleBorder( + RoundedRectangleBorder( side: widget.borderSide ?? BorderSide( color: Theme.of(context).brightness == Brightness.dark diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 0d37d87f..a166e4da 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -40,6 +40,7 @@ class ReactionBubble extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(14)), ), child: Wrap( + spacing: 8, children: [ ...reactions.map((reaction) { final reactionIcon = reactionIcons.firstWhere( diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 5855b59f..f954902b 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -45,7 +45,7 @@ class ReactionPicker extends StatelessWidget { reactionIcon.iconData, color: ownReactionIndex != -1 ? StreamChatTheme.of(context).accentColor - : Theme.of(context).iconTheme.color, + : Theme.of(context).iconTheme.color.withOpacity(.5), ), onPressed: () { if (ownReactionIndex != -1) { From 886b9faf3762e728c5b0e1d5f4ca1407256eb777 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:26:36 +0200 Subject: [PATCH 02/15] fix message reaction modal --- lib/src/message_reactions_modal.dart | 124 ++++++++++++++------------- 1 file changed, 63 insertions(+), 61 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index b30f92b3..a7557146 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -119,30 +119,26 @@ class MessageReactionsModal extends StatelessWidget { ), ), Flexible( - child: Padding( - padding: const EdgeInsets.only( - left: 16.0, - right: 16, - bottom: 16, - ), - child: GridView.builder( - shrinkWrap: true, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 16, - childAspectRatio: 0.75, - mainAxisSpacing: 22, + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.only( + left: 18, + right: 18, + bottom: 26, + ), + child: Wrap( + spacing: 16, + runSpacing: 22, + alignment: WrapAlignment.start, + children: + [...message.latestReactions, ...message.latestReactions] + .map((e) => _buildReaction( + e, + currentUser, + context, + )) + .toList(), ), - itemCount: message.latestReactions.length, - itemBuilder: (context, i) { - final reaction = message.latestReactions[i]; - - return _buildReaction( - reaction, - currentUser, - context, - ); - }, ), ), ), @@ -152,51 +148,57 @@ class MessageReactionsModal extends StatelessWidget { ); } - Column _buildReaction( + Widget _buildReaction( Reaction reaction, User currentUser, BuildContext context, ) { final isCurrentUser = reaction.user.id == currentUser.id; - return Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Stack( - children: [ - UserAvatar( - onTap: onUserAvatarTap, - user: reaction.user, - constraints: BoxConstraints.tightFor( - height: 64, - width: 64, + return ConstrainedBox( + constraints: BoxConstraints.loose(Size( + 64, + 98, + )), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Stack( + children: [ + UserAvatar( + onTap: onUserAvatarTap, + user: reaction.user, + constraints: BoxConstraints.tightFor( + height: 64, + width: 64, + ), + borderRadius: BorderRadius.circular(32), ), - borderRadius: BorderRadius.circular(32), - ), - Positioned( - child: ReactionBubble( - reactions: [reaction], - borderColor: isCurrentUser - ? messageTheme.ownReactionsBorderColor - : messageTheme.otherReactionsBorderColor, - backgroundColor: isCurrentUser - ? messageTheme.ownReactionsBackgroundColor - : messageTheme.otherReactionsBackgroundColor, - flipTail: !isCurrentUser, + Positioned( + child: ReactionBubble( + reactions: [reaction], + borderColor: isCurrentUser + ? messageTheme.ownReactionsBorderColor + : messageTheme.otherReactionsBorderColor, + backgroundColor: isCurrentUser + ? messageTheme.ownReactionsBackgroundColor + : messageTheme.otherReactionsBackgroundColor, + flipTail: !isCurrentUser, + ), + bottom: 0, + left: isCurrentUser ? 0 : null, + right: isCurrentUser ? 0 : null, ), - bottom: 0, - left: isCurrentUser ? 0 : null, - right: isCurrentUser ? 0 : null, - ), - ], - ), - Text( - reaction.user.name, - style: Theme.of(context).textTheme.subtitle2, - textAlign: TextAlign.center, - ), - ], + ], + ), + Text( + reaction.user.name, + style: Theme.of(context).textTheme.subtitle2, + textAlign: TextAlign.center, + ), + ], + ), ); } } From 3980ddde578bbe7b2a856d1748fa5f8417bab188 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:28:45 +0200 Subject: [PATCH 03/15] fix message reaction modal --- lib/src/message_reactions_modal.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index a7557146..6ee5bf51 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -131,7 +131,7 @@ class MessageReactionsModal extends StatelessWidget { runSpacing: 22, alignment: WrapAlignment.start, children: - [...message.latestReactions, ...message.latestReactions] + message.latestReactions .map((e) => _buildReaction( e, currentUser, From eebe2ce171b57501046dffdf4c910f6dccb90811 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 21 Oct 2020 10:30:40 +0200 Subject: [PATCH 04/15] fix message reaction modal --- lib/src/message_reactions_modal.dart | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 6ee5bf51..56e49382 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -130,14 +130,13 @@ class MessageReactionsModal extends StatelessWidget { spacing: 16, runSpacing: 22, alignment: WrapAlignment.start, - children: - message.latestReactions - .map((e) => _buildReaction( - e, - currentUser, - context, - )) - .toList(), + children: message.latestReactions + .map((e) => _buildReaction( + e, + currentUser, + context, + )) + .toList(), ), ), ), From ba37258427b48a7b8fa99b2821fcb77df5c756f9 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 09:58:15 +0100 Subject: [PATCH 05/15] wip --- lib/src/message_actions_modal.dart | 12 ++- lib/src/message_list_view.dart | 2 +- lib/src/message_reactions_modal.dart | 31 ++++--- lib/src/message_widget.dart | 116 ++++++++--------------- lib/src/reaction_bubble.dart | 132 +++++++++++++++++---------- lib/src/reaction_picker.dart | 7 +- lib/src/stream_chat.dart | 23 ++--- lib/src/stream_chat_theme.dart | 44 +++------ 8 files changed, 171 insertions(+), 196 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 714966ce..ded377fc 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -79,10 +79,14 @@ class MessageActionsModal extends StatelessWidget { child: MessageWidget( key: Key('MessageWidget'), reverse: reverse, - message: message.text.length > 200 - ? message.copyWith( - text: '${message.text.substring(0, 200)}...') - : message, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + attachments: message.attachments.length > 1 + ? [message.attachments[0]] + : message.attachments, + ), messageTheme: messageTheme, showReactions: false, showUsername: false, diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7c529f95..87d79622 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -543,7 +543,7 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - showUserAvatar: isMyMessage + showUserAvatar: !isMyMessage ? DisplayWidget.gone : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), messageTheme: isMyMessage diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 56e49382..9d2a30bf 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -70,10 +70,14 @@ class MessageReactionsModal extends StatelessWidget { child: MessageWidget( key: Key('MessageWidget'), reverse: reverse, - message: message.text.length > 200 - ? message.copyWith( - text: '${message.text.substring(0, 200)}...') - : message, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + attachments: message.attachments.length > 1 + ? [message.attachments[0]] + : message.attachments, + ), messageTheme: messageTheme, showReactions: false, showUsername: false, @@ -175,15 +179,16 @@ class MessageReactionsModal extends StatelessWidget { borderRadius: BorderRadius.circular(32), ), Positioned( - child: ReactionBubble( - reactions: [reaction], - borderColor: isCurrentUser - ? messageTheme.ownReactionsBorderColor - : messageTheme.otherReactionsBorderColor, - backgroundColor: isCurrentUser - ? messageTheme.ownReactionsBackgroundColor - : messageTheme.otherReactionsBackgroundColor, - flipTail: !isCurrentUser, + child: Align( + alignment: Alignment.centerLeft, + child: Container( + child: ReactionBubble( + reactions: [reaction], + borderColor: messageTheme.reactionsBorderColor, + backgroundColor: messageTheme.reactionsBackgroundColor, + flipTail: !isCurrentUser, + ), + ), ), bottom: 0, left: isCurrentUser ? 0 : null, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 10298436..9a2200c3 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -239,20 +239,23 @@ class _MessageWidgetState extends State { 8, ), Flexible( - child: Padding( - padding: widget.showReactions - ? EdgeInsets.only( - top: widget.message.reactionCounts - ?.isNotEmpty == - true - ? 12 - : 0, - ) - : EdgeInsets.zero, - child: PortalEntry( - portalAnchor: Alignment(-0.81, 0), - childAnchor: Alignment.topRight, - portal: _buildReactionIndicator(context), + child: PortalEntry( + portal: ConstrainedBox( + child: _buildReactionIndicator(context), + constraints: BoxConstraints(maxWidth: 22 * 6.0), + ), + portalAnchor: Alignment(-1.0, -1.0), + childAnchor: Alignment(1, -1.0), + child: Padding( + padding: widget.showReactions + ? EdgeInsets.only( + top: widget.message.reactionCounts + ?.isNotEmpty == + true + ? 18 + : 0, + ) + : EdgeInsets.zero, child: (widget.message.isDeleted && widget.message.status != MessageSendingStatus.FAILED_DELETE) @@ -378,74 +381,33 @@ class _MessageWidgetState extends State { ); } - Widget _buildReactionIndicator(BuildContext context) { - final otherReactions = widget.message.latestReactions - ?.where( - (element) => element.user.id != StreamChat.of(context).user.id) - ?.toList() ?? - []; + Widget _buildReactionIndicator( + BuildContext context, + ) { + final ownId = StreamChat.of(context).user.id; + final reactionsMap = {}; + widget.message.latestReactions.forEach((element) { + if (!reactionsMap.containsKey(element.type) || element.user.id == ownId) { + reactionsMap[element.type] = element; + } + }); - var rowChildren = [ - if (widget.message.ownReactions?.isNotEmpty == true) ...[ - Transform.translate( - offset: Offset( - widget.reverse ? -6 : 0, - 0, - ), - child: ReactionBubble( - key: ValueKey('${widget.message.id}.own'), - reverse: widget.reverse, - backgroundColor: widget.messageTheme.ownReactionsBackgroundColor, - borderColor: widget.messageTheme.ownReactionsBorderColor, - reactions: widget.message.ownReactions, - ), - ), - if (otherReactions.isEmpty) - Container( - width: 18, - ), - ], - if (otherReactions?.isNotEmpty == true) ...[ - if (widget.message.ownReactions?.isEmpty == true) - Container( - width: 18, - ), - Transform.translate( - offset: Offset( - widget.reverse ? 0 : -6, - 0, - ), - child: ReactionBubble( - key: ValueKey('${widget.message.id}.other'), - reactions: otherReactions, - reverse: widget.reverse, - flipTail: true, - backgroundColor: widget.messageTheme.otherReactionsBackgroundColor, - borderColor: widget.messageTheme.otherReactionsBorderColor, - ), - ), - ] - ]; - - if (widget.reverse) { - rowChildren = rowChildren.reversed.toList(); - } return AnimatedSwitcher( duration: Duration(milliseconds: 300), child: (widget.showReactions && - (widget.message.reactionCounts?.isNotEmpty == true || - otherReactions.isNotEmpty) && + (widget.message.reactionCounts?.isNotEmpty == true) && !widget.message.isDeleted) - ? Container( - child: GestureDetector( - onTap: () => _showMessageReactionsModalBottomSheet(context), - child: FractionallySizedBox( - widthFactor: 0.5, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: rowChildren, - ), + ? GestureDetector( + onTap: () => _showMessageReactionsModalBottomSheet(context), + child: Transform.translate( + offset: Offset(-16, 0), + child: ReactionBubble( + key: ValueKey('${widget.message.id}.reactions'), + reverse: widget.reverse, + flipTail: widget.reverse, + backgroundColor: widget.messageTheme.reactionsBackgroundColor, + borderColor: widget.messageTheme.reactionsBorderColor, + reactions: reactionsMap.values.toList(), ), ), ) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index a166e4da..9db6e112 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -1,6 +1,8 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; class ReactionBubble extends StatelessWidget { @@ -25,60 +27,92 @@ class ReactionBubble extends StatelessWidget { return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, - child: Column( - crossAxisAlignment: - flipTail ? CrossAxisAlignment.start : CrossAxisAlignment.end, - mainAxisSize: MainAxisSize.min, + child: Stack( + alignment: Alignment.center, children: [ - Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - border: Border.all( - color: borderColor, + Transform.translate( + offset: Offset(reverse ? 5 : -5, 0), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 6), + decoration: BoxDecoration( + border: Border.all( + color: borderColor, + ), + color: backgroundColor, + borderRadius: BorderRadius.all(Radius.circular(14)), ), - color: backgroundColor, - borderRadius: BorderRadius.all(Radius.circular(14)), - ), - child: Wrap( - spacing: 8, - children: [ - ...reactions.map((reaction) { - final reactionIcon = reactionIcons.firstWhere( - (r) => r.type == reaction.type, - orElse: () => null, + child: LayoutBuilder( + builder: (context, constraints) { + return Flex( + direction: Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + if (constraints.maxWidth < double.infinity) + ...reactions + .take((constraints.maxWidth) ~/ 22) + .map((reaction) { + return _buildReaction( + reactionIcons, + reaction, + context, + ); + }).toList(), + if (constraints.maxWidth == double.infinity) + ...reactions.map((reaction) { + return _buildReaction( + reactionIcons, + reaction, + context, + ); + }).toList(), + ], ); - if (reactionIcon == null) { - return Text( - '?', - style: TextStyle( - color: StreamChatTheme.of(context).accentColor, - ), - ); - } - - return Icon( - reactionIcon.iconData, - size: 16, - color: StreamChatTheme.of(context).accentColor, - ); - }).toList(), - ], + }, + ), ), ), - _buildReactionsTail(context), + Positioned( + bottom: 0, + left: reverse ? null : 16, + right: !reverse ? null : 16, + child: _buildReactionsTail(context), + ), ], ), ); } + Widget _buildReaction( + List reactionIcons, + Reaction reaction, + BuildContext context, + ) { + final reactionIcon = reactionIcons.firstWhere( + (r) => r.type == reaction.type, + orElse: () => null, + ); + + return Padding( + padding: const EdgeInsets.symmetric( + horizontal: 4.0, + ), + child: Icon( + reactionIcon?.iconData ?? Icons.help_outline_rounded, + size: 16, + color: reaction.user.id == StreamChat.of(context).user.id + ? StreamChatTheme.of(context).accentColor + : Colors.black.withOpacity(.5), + ), + ); + } + Widget _buildReactionsTail(BuildContext context) { final tail = Transform.translate( - offset: Offset(reactions.length > 1 ? -9 : -9, 0), + offset: Offset(-5, 0), child: CustomPaint( painter: ReactionBubblePainter( backgroundColor, borderColor, - reactions.length, ), ), ); @@ -98,12 +132,10 @@ class ReactionBubble extends StatelessWidget { class ReactionBubblePainter extends CustomPainter { final Color color; final Color borderColor; - final int reactionsCount; ReactionBubblePainter( this.color, this.borderColor, - this.reactionsCount, ); @override @@ -126,7 +158,7 @@ class ReactionBubblePainter extends CustomPainter { final path = Path(); path.addOval( Rect.fromCircle( - center: Offset(6, 2), + center: Offset(4, 3), radius: 2, ), ); @@ -140,7 +172,7 @@ class ReactionBubblePainter extends CustomPainter { final path = Path(); path.addOval(Rect.fromCircle( - center: Offset(6, 2), + center: Offset(4, 3), radius: 2, )); canvas.drawPath(path, paint); @@ -152,13 +184,13 @@ class ReactionBubblePainter extends CustomPainter { ..strokeWidth = 1 ..style = PaintingStyle.stroke; - final dy = reactionsCount > 1 ? -2.0 : -3.0; - final startAngle = reactionsCount > 1 ? 1.08 : 1.16; - final sweepAngle = reactionsCount > 1 ? 0.95 : 1.1; + final dy = -2.2; + final startAngle = 1.1; + final sweepAngle = 1.2; final path = Path(); path.addArc( Rect.fromCircle( - center: Offset(0, dy), + center: Offset(1, dy), radius: 4, ), -pi * startAngle, @@ -172,13 +204,13 @@ class ReactionBubblePainter extends CustomPainter { ..color = color ..strokeWidth = 1; - final dy = reactionsCount > 1 ? -2.0 : -3.0; - final startAngle = reactionsCount > 1 ? 1 : 1.16; - final sweepAngle = reactionsCount > 1 ? 1.2 : 1; + final dy = -2.2; + final startAngle = 1; + final sweepAngle = 1.3; final path = Path(); path.addArc( Rect.fromCircle( - center: Offset(0, dy), + center: Offset(1, dy), radius: 4, ), -pi * startAngle, diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index f954902b..87487cde 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -26,7 +26,7 @@ class ReactionPicker extends StatelessWidget { fit: StackFit.passthrough, children: [ Material( - color: messageTheme.ownReactionsBackgroundColor, + color: messageTheme.reactionsBackgroundColor, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), @@ -69,9 +69,8 @@ class ReactionPicker extends StatelessWidget { bottom: 0, child: CustomPaint( painter: ReactionBubblePainter( - messageTheme.ownReactionsBackgroundColor, - messageTheme.ownReactionsBorderColor, - 2, + messageTheme.reactionsBackgroundColor, + messageTheme.reactionsBorderColor, ), ), ), diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index b22c257c..e8eca6d6 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -129,14 +129,9 @@ class StreamChatState extends State with WidgetsBindingObserver { constraints: themeData?.ownMessageTheme?.avatarTheme?.constraints, borderRadius: themeData?.ownMessageTheme?.avatarTheme?.borderRadius, ), - otherReactionsBorderColor: - themeData?.ownMessageTheme?.otherReactionsBorderColor, - otherReactionsBackgroundColor: - themeData?.ownMessageTheme?.otherReactionsBackgroundColor, - ownReactionsBackgroundColor: - themeData?.ownMessageTheme?.ownReactionsBackgroundColor, - ownReactionsBorderColor: - themeData?.ownMessageTheme?.ownReactionsBorderColor, + reactionsBorderColor: themeData?.ownMessageTheme?.reactionsBorderColor, + reactionsBackgroundColor: + themeData?.ownMessageTheme?.reactionsBackgroundColor, ), otherMessageTheme: defaultTheme.otherMessageTheme.copyWith( replies: themeData?.otherMessageTheme?.replies, @@ -150,14 +145,10 @@ class StreamChatState extends State with WidgetsBindingObserver { constraints: themeData?.otherMessageTheme?.avatarTheme?.constraints, borderRadius: themeData?.otherMessageTheme?.avatarTheme?.borderRadius, ), - otherReactionsBorderColor: - themeData?.otherMessageTheme?.otherReactionsBorderColor, - otherReactionsBackgroundColor: - themeData?.otherMessageTheme?.otherReactionsBackgroundColor, - ownReactionsBackgroundColor: - themeData?.otherMessageTheme?.ownReactionsBackgroundColor, - ownReactionsBorderColor: - themeData?.otherMessageTheme?.ownReactionsBorderColor, + reactionsBorderColor: + themeData?.otherMessageTheme?.reactionsBorderColor, + reactionsBackgroundColor: + themeData?.otherMessageTheme?.reactionsBackgroundColor, ), accentColor: themeData?.accentColor, secondaryColor: themeData?.secondaryColor, diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 359ab102..504864b2 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -302,12 +302,8 @@ class StreamChatThemeData { fontSize: 12, ), messageBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), - ownReactionsBackgroundColor: - isDark ? Color(0xff191919) : Color(0xffEAEAEA), - ownReactionsBorderColor: isDark ? Colors.black : Colors.white, - otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white, - otherReactionsBorderColor: - isDark ? Color(0xff191919) : Color(0xffEAEAEA), + reactionsBackgroundColor: isDark ? Colors.black : Colors.white, + reactionsBorderColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: BoxConstraints.tightFor( @@ -320,12 +316,9 @@ class StreamChatThemeData { ), ), otherMessageTheme: MessageTheme( - ownReactionsBackgroundColor: - isDark ? Color(0xff191919) : Color(0xffEAEAEA), - ownReactionsBorderColor: isDark ? Colors.black : Colors.white, - otherReactionsBackgroundColor: isDark ? Colors.black : Colors.white, - otherReactionsBorderColor: + reactionsBackgroundColor: isDark ? Color(0xff191919) : Color(0xffEAEAEA), + reactionsBorderColor: isDark ? Colors.black : Colors.white, messageText: TextStyle( fontSize: 15, color: isDark ? Colors.white : Colors.black, @@ -457,10 +450,8 @@ class MessageTheme { final TextStyle createdAt; final TextStyle replies; final Color messageBackgroundColor; - final Color ownReactionsBackgroundColor; - final Color ownReactionsBorderColor; - final Color otherReactionsBackgroundColor; - final Color otherReactionsBorderColor; + final Color reactionsBackgroundColor; + final Color reactionsBorderColor; final AvatarTheme avatarTheme; const MessageTheme({ @@ -469,10 +460,8 @@ class MessageTheme { this.messageAuthor, this.messageLinks, this.messageBackgroundColor, - this.ownReactionsBackgroundColor, - this.ownReactionsBorderColor, - this.otherReactionsBackgroundColor, - this.otherReactionsBorderColor, + this.reactionsBackgroundColor, + this.reactionsBorderColor, this.avatarTheme, this.createdAt, }); @@ -485,10 +474,8 @@ class MessageTheme { TextStyle replies, Color messageBackgroundColor, AvatarTheme avatarTheme, - Color ownReactionsBackgroundColor, - Color ownReactionsBorderColor, - Color otherReactionsBackgroundColor, - Color otherReactionsBorderColor, + Color reactionsBackgroundColor, + Color reactionsBorderColor, }) => MessageTheme( messageText: messageText ?? this.messageText, @@ -499,14 +486,9 @@ class MessageTheme { messageBackgroundColor ?? this.messageBackgroundColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, - ownReactionsBackgroundColor: - ownReactionsBackgroundColor ?? this.ownReactionsBackgroundColor, - ownReactionsBorderColor: - ownReactionsBorderColor ?? this.ownReactionsBorderColor, - otherReactionsBackgroundColor: - otherReactionsBackgroundColor ?? this.otherReactionsBackgroundColor, - otherReactionsBorderColor: - otherReactionsBorderColor ?? this.otherReactionsBorderColor, + reactionsBackgroundColor: + reactionsBackgroundColor ?? this.reactionsBackgroundColor, + reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, ); } From 58511e8f4bfe277deb41aa11361643c493a84421 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 10:32:22 +0100 Subject: [PATCH 06/15] fix reactions ontap --- example/ios/Flutter/.last_build_id | 2 +- example/lib/main.dart | 2 +- example/pubspec.yaml | 2 +- lib/src/message_list_view.dart | 2 +- lib/src/message_reactions_modal.dart | 97 ++++++++++++++-------------- lib/src/message_widget.dart | 20 +++--- lib/src/reaction_bubble.dart | 24 +++---- 7 files changed, 75 insertions(+), 74 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 171fde31..661f8167 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -0289cdadbd29bab804f275e3c5907d07 \ No newline at end of file +89eb023669fee58472de747080d78b5a \ No newline at end of file diff --git a/example/lib/main.dart b/example/lib/main.dart index 89ed9381..667b1e0f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -76,7 +76,7 @@ void main() async { await client.setUser( User(id: 'super-band-9', extraData: { - 'name': 'John Doe', + 'name': 'Jonathan Doe', }), 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A', ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9a6554e6..cb0eca8e 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.31+33 +version: 1.0.32+34 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 87d79622..7c529f95 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -543,7 +543,7 @@ class _MessageListViewState extends State { topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), - showUserAvatar: !isMyMessage + showUserAvatar: isMyMessage ? DisplayWidget.gone : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), messageTheme: isMyMessage diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 9d2a30bf..319b8acd 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -53,49 +53,54 @@ class MessageReactionsModal extends StatelessWidget { ), ), ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), + AbsorbPointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + attachments: message.attachments.length > 1 + ? [message.attachments[0]] + : message.attachments, + ), messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, ), ), - AbsorbPointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - attachments: message.attachments.length > 1 - ? [message.attachments[0]] - : message.attachments, + SizedBox( + height: 16, + ), + if (message.latestReactions?.isNotEmpty == true) + Flexible( + child: Container( + constraints: BoxConstraints.loose(Size.fromHeight(400)), + child: _buildReactionCard(context), + ), ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, - ), - ), - SizedBox( - height: 16, - ), - if (message.latestReactions?.isNotEmpty == true) - Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - child: _buildReactionCard(context), - ), - ], + ], + ), ), ], ); @@ -181,16 +186,14 @@ class MessageReactionsModal extends StatelessWidget { Positioned( child: Align( alignment: Alignment.centerLeft, - child: Container( - child: ReactionBubble( - reactions: [reaction], - borderColor: messageTheme.reactionsBorderColor, - backgroundColor: messageTheme.reactionsBackgroundColor, - flipTail: !isCurrentUser, - ), + child: ReactionBubble( + reactions: [reaction], + borderColor: messageTheme.reactionsBorderColor, + backgroundColor: messageTheme.reactionsBackgroundColor, + highlightOwnReactions: false, ), ), - bottom: 0, + bottom: 4, left: isCurrentUser ? 0 : null, right: isCurrentUser ? 0 : null, ), diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 9a2200c3..beff166a 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -240,7 +240,8 @@ class _MessageWidgetState extends State { ), Flexible( child: PortalEntry( - portal: ConstrainedBox( + portal: Container( + transform: Matrix4.translationValues(-16, 0, 0), child: _buildReactionIndicator(context), constraints: BoxConstraints(maxWidth: 22 * 6.0), ), @@ -399,16 +400,13 @@ class _MessageWidgetState extends State { !widget.message.isDeleted) ? GestureDetector( onTap: () => _showMessageReactionsModalBottomSheet(context), - child: Transform.translate( - offset: Offset(-16, 0), - child: ReactionBubble( - key: ValueKey('${widget.message.id}.reactions'), - reverse: widget.reverse, - flipTail: widget.reverse, - backgroundColor: widget.messageTheme.reactionsBackgroundColor, - borderColor: widget.messageTheme.reactionsBorderColor, - reactions: reactionsMap.values.toList(), - ), + child: ReactionBubble( + key: ValueKey('${widget.message.id}.reactions'), + reverse: widget.reverse, + flipTail: widget.reverse, + backgroundColor: widget.messageTheme.reactionsBackgroundColor, + borderColor: widget.messageTheme.reactionsBorderColor, + reactions: reactionsMap.values.toList(), ), ) : SizedBox(), diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 9db6e112..03f415b0 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -13,6 +13,7 @@ class ReactionBubble extends StatelessWidget { @required this.backgroundColor, this.reverse = false, this.flipTail = false, + this.highlightOwnReactions = true, }) : super(key: key); final List reactions; @@ -20,6 +21,7 @@ class ReactionBubble extends StatelessWidget { final Color backgroundColor; final bool reverse; final bool flipTail; + final bool highlightOwnReactions; @override Widget build(BuildContext context) { @@ -31,9 +33,9 @@ class ReactionBubble extends StatelessWidget { alignment: Alignment.center, children: [ Transform.translate( - offset: Offset(reverse ? 5 : -5, 0), + offset: Offset(reverse ? 2 : -2, 0), child: Container( - padding: const EdgeInsets.symmetric(vertical: 6), + padding: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( border: Border.all( color: borderColor, @@ -73,8 +75,8 @@ class ReactionBubble extends StatelessWidget { ), Positioned( bottom: 0, - left: reverse ? null : 16, - right: !reverse ? null : 16, + left: reverse ? null : 11, + right: !reverse ? null : 11, child: _buildReactionsTail(context), ), ], @@ -99,7 +101,8 @@ class ReactionBubble extends StatelessWidget { child: Icon( reactionIcon?.iconData ?? Icons.help_outline_rounded, size: 16, - color: reaction.user.id == StreamChat.of(context).user.id + color: (!highlightOwnReactions || + reaction.user.id == StreamChat.of(context).user.id) ? StreamChatTheme.of(context).accentColor : Colors.black.withOpacity(.5), ), @@ -107,13 +110,10 @@ class ReactionBubble extends StatelessWidget { } Widget _buildReactionsTail(BuildContext context) { - final tail = Transform.translate( - offset: Offset(-5, 0), - child: CustomPaint( - painter: ReactionBubblePainter( - backgroundColor, - borderColor, - ), + final tail = CustomPaint( + painter: ReactionBubblePainter( + backgroundColor, + borderColor, ), ); From e8411d3aa4fe39cb7907da22f5ea6397d16cf5c8 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 16:15:50 +0100 Subject: [PATCH 07/15] fix reactions overflowing the screen --- lib/src/message_actions_modal.dart | 127 ++++++++++++++------------- lib/src/message_reactions_modal.dart | 2 +- lib/src/message_widget.dart | 2 +- lib/src/reaction_bubble.dart | 3 +- 4 files changed, 71 insertions(+), 63 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index ded377fc..c1c572a7 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -62,71 +62,78 @@ class MessageActionsModal extends StatelessWidget { ), ), ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + attachments: message.attachments.length > 1 + ? [message.attachments[0]] + : message.attachments, + ), messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, ), ), - AbsorbPointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - attachments: message.attachments.length > 1 - ? [message.attachments[0]] - : message.attachments, - ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, + SizedBox( + height: 8, ), - ), - SizedBox( - height: 8, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 48.0, - ), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + Flexible( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 48.0, + ), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: ListTile.divideTiles( + context: context, + tiles: [ + if (showReply && + (message.status == MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildReplyButton(context), + if (showEditMessage) _buildEditMessage(context), + if (showDeleteMessage) _buildDeleteButton(context), + if (showCopyMessage) _buildCopyButton(context), + ], + ).toList(), + ), + ), + ), ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: ListTile.divideTiles( - context: context, - tiles: [ - if (showReply && - (message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) - _buildReplyButton(context), - if (showEditMessage) _buildEditMessage(context), - if (showDeleteMessage) _buildDeleteButton(context), - if (showCopyMessage) _buildCopyButton(context), - ], - ).toList(), - ), - ), - ) - ], + ) + ], + ), ), ], ); diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 319b8acd..b6026cf7 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -68,7 +68,7 @@ class MessageReactionsModal extends StatelessWidget { messageTheme: messageTheme, ), ), - AbsorbPointer( + IgnorePointer( child: MessageWidget( key: Key('MessageWidget'), reverse: reverse, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index beff166a..a2c886af 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -387,7 +387,7 @@ class _MessageWidgetState extends State { ) { final ownId = StreamChat.of(context).user.id; final reactionsMap = {}; - widget.message.latestReactions.forEach((element) { + widget.message.latestReactions?.forEach((element) { if (!reactionsMap.containsKey(element.type) || element.user.id == ownId) { reactionsMap[element.type] = element; } diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 03f415b0..83593afc 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -26,6 +26,7 @@ class ReactionBubble extends StatelessWidget { @override Widget build(BuildContext context) { final reactionIcons = StreamChatTheme.of(context).reactionIcons; + final offset = reactions.length > 1 ? 16.0 : 2.0; return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, @@ -33,7 +34,7 @@ class ReactionBubble extends StatelessWidget { alignment: Alignment.center, children: [ Transform.translate( - offset: Offset(reverse ? 2 : -2, 0), + offset: Offset(reverse ? offset : -offset, 0), child: Container( padding: const EdgeInsets.symmetric(vertical: 4), decoration: BoxDecoration( From e9572d48b9b2971fddafe7f2f6723a8072cc884a Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 16:56:51 +0100 Subject: [PATCH 08/15] put own reaction to the right --- lib/src/message_actions_modal.dart | 140 +++++++++++++-------------- lib/src/message_reactions_modal.dart | 121 +++++++++++------------ lib/src/message_widget.dart | 4 +- 3 files changed, 129 insertions(+), 136 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index c1c572a7..582e8496 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -43,75 +43,71 @@ class MessageActionsModal extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - Positioned.fill( - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context); - }, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context); + }, + child: SingleChildScrollView( + padding: const EdgeInsets.only(top: 160), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: Colors.transparent, + ), ), ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, - messageTheme: messageTheme, - ), - ), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - attachments: message.attachments.length > 1 - ? [message.attachments[0]] - : message.attachments, - ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, - ), - ), - SizedBox( - height: 8, - ), - Flexible( - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 48.0, - ), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), ), - child: SingleChildScrollView( + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + ), + messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, + ), + ), + SizedBox( + height: 8, + ), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 48.0, + ), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: ListTile.divideTiles( @@ -129,13 +125,13 @@ class MessageActionsModal extends StatelessWidget { ).toList(), ), ), - ), - ), - ) - ], - ), + ) + ], + ), + ), + ], ), - ], + ), ); } diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index b6026cf7..7db22ee1 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -34,75 +34,70 @@ class MessageReactionsModal extends StatelessWidget { @override Widget build(BuildContext context) { - return Stack( - children: [ - Positioned.fill( - child: GestureDetector( - behavior: HitTestBehavior.translucent, - onTap: () { - Navigator.pop(context); - }, - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, + return GestureDetector( + behavior: HitTestBehavior.translucent, + onTap: () { + Navigator.pop(context); + }, + child: SingleChildScrollView( + padding: const EdgeInsets.only(top: 160), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: Colors.transparent, + ), ), ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, - messageTheme: messageTheme, + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + ), + messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, + ), ), - ), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - attachments: message.attachments.length > 1 - ? [message.attachments[0]] - : message.attachments, + SizedBox( + height: 16, ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, - ), + if (message.latestReactions?.isNotEmpty == true) + _buildReactionCard(context), + ], ), - SizedBox( - height: 16, - ), - if (message.latestReactions?.isNotEmpty == true) - Flexible( - child: Container( - constraints: BoxConstraints.loose(Size.fromHeight(400)), - child: _buildReactionCard(context), - ), - ), - ], - ), + ), + ], ), - ], + ), ); } diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index a2c886af..c3fa4c6e 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -392,6 +392,8 @@ class _MessageWidgetState extends State { reactionsMap[element.type] = element; } }); + final reactionsList = reactionsMap.values.toList() + ..sort((a, b) => a.user.id == ownId ? 1 : -1); return AnimatedSwitcher( duration: Duration(milliseconds: 300), @@ -406,7 +408,7 @@ class _MessageWidgetState extends State { flipTail: widget.reverse, backgroundColor: widget.messageTheme.reactionsBackgroundColor, borderColor: widget.messageTheme.reactionsBorderColor, - reactions: reactionsMap.values.toList(), + reactions: reactionsList, ), ) : SizedBox(), From d2801b2b1324a7d62915c9e0b1938245e5477ead Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Tue, 27 Oct 2020 17:11:57 +0100 Subject: [PATCH 09/15] fix scrollview --- lib/src/message_actions_modal.dart | 149 ++++++++++++++------------- lib/src/message_reactions_modal.dart | 101 +++++++++--------- lib/src/message_widget.dart | 2 +- 3 files changed, 128 insertions(+), 124 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 582e8496..4b6c4d4f 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -48,88 +48,91 @@ class MessageActionsModal extends StatelessWidget { onTap: () { Navigator.pop(context); }, - child: SingleChildScrollView( - padding: const EdgeInsets.only(top: 160), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, + child: Center( + child: SingleChildScrollView( + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: Colors.transparent, + ), ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + ), messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, ), ), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, + SizedBox( + height: 8, ), - ), - SizedBox( - height: 8, - ), - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 48.0, - ), - child: Material( - clipBehavior: Clip.hardEdge, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 48.0, ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: ListTile.divideTiles( - context: context, - tiles: [ - if (showReply && - (message.status == MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) - _buildReplyButton(context), - if (showEditMessage) _buildEditMessage(context), - if (showDeleteMessage) _buildDeleteButton(context), - if (showCopyMessage) _buildCopyButton(context), - ], - ).toList(), + child: Material( + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: ListTile.divideTiles( + context: context, + tiles: [ + if (showReply && + (message.status == + MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildReplyButton(context), + if (showEditMessage) _buildEditMessage(context), + if (showDeleteMessage) + _buildDeleteButton(context), + if (showCopyMessage) _buildCopyButton(context), + ], + ).toList(), + ), ), - ), - ) - ], + ) + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 7db22ee1..0582eb79 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -39,63 +39,64 @@ class MessageReactionsModal extends StatelessWidget { onTap: () { Navigator.pop(context); }, - child: SingleChildScrollView( - padding: const EdgeInsets.only(top: 160), - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, + child: Center( + child: SingleChildScrollView( + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10, + sigmaY: 10, + ), + child: Container( + color: Colors.transparent, + ), ), ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (showReactions && - (message.status == MessageSendingStatus.SENT || - message.status == null)) - Center( - child: ReactionPicker( - message: message, + Padding( + padding: const EdgeInsets.symmetric(vertical: 8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + if (showReactions && + (message.status == MessageSendingStatus.SENT || + message.status == null)) + Center( + child: ReactionPicker( + message: message, + messageTheme: messageTheme, + ), + ), + IgnorePointer( + child: MessageWidget( + key: Key('MessageWidget'), + reverse: reverse, + message: message.copyWith( + text: message.text.length > 200 + ? '${message.text.substring(0, 200)}...' + : message.text, + ), messageTheme: messageTheme, + showReactions: false, + showUsername: false, + showReplyIndicator: false, + showTimestamp: false, + showSendingIndicator: DisplayWidget.gone, + shape: messageShape, ), ), - IgnorePointer( - child: MessageWidget( - key: Key('MessageWidget'), - reverse: reverse, - message: message.copyWith( - text: message.text.length > 200 - ? '${message.text.substring(0, 200)}...' - : message.text, - ), - messageTheme: messageTheme, - showReactions: false, - showUsername: false, - showReplyIndicator: false, - showTimestamp: false, - showSendingIndicator: DisplayWidget.gone, - shape: messageShape, + SizedBox( + height: 16, ), - ), - SizedBox( - height: 16, - ), - if (message.latestReactions?.isNotEmpty == true) - _buildReactionCard(context), - ], + if (message.latestReactions?.isNotEmpty == true) + _buildReactionCard(context), + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index c3fa4c6e..0e703fa0 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -241,7 +241,7 @@ class _MessageWidgetState extends State { Flexible( child: PortalEntry( portal: Container( - transform: Matrix4.translationValues(-16, 0, 0), + transform: Matrix4.translationValues(-16, 2, 0), child: _buildReactionIndicator(context), constraints: BoxConstraints(maxWidth: 22 * 6.0), ), From 3f619fe79c4a8a95f52c70896781d13738c53cee Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 10:39:55 +0100 Subject: [PATCH 10/15] fix backdrop filter --- lib/src/message_actions_modal.dart | 38 +++++++++++++++------------- lib/src/message_reactions_modal.dart | 38 +++++++++++++++------------- lib/src/stream_chat_theme.dart | 8 +++--- 3 files changed, 46 insertions(+), 38 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 4b6c4d4f..54108df7 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -43,27 +43,28 @@ class MessageActionsModal extends StatelessWidget { @override Widget build(BuildContext context) { + final ownId = StreamChat.of(context).user.id; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Navigator.pop(context); }, - child: Center( - child: SingleChildScrollView( - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, - ), - ), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10.8731, + sigmaY: 10.8731, ), - Padding( + child: Container( + color: Colors.black.withOpacity(0.2), + ), + ), + ), + Center( + child: SingleChildScrollView( + child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -91,6 +92,9 @@ class MessageActionsModal extends StatelessWidget { showReactions: false, showUsername: false, showReplyIndicator: false, + showUserAvatar: message.user.id == ownId + ? DisplayWidget.gone + : DisplayWidget.show, showTimestamp: false, showSendingIndicator: DisplayWidget.gone, shape: messageShape, @@ -131,9 +135,9 @@ class MessageActionsModal extends StatelessWidget { ], ), ), - ], + ), ), - ), + ], ), ); } diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 0582eb79..375da94e 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -34,27 +34,28 @@ class MessageReactionsModal extends StatelessWidget { @override Widget build(BuildContext context) { + final ownId = StreamChat.of(context).user.id; return GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { Navigator.pop(context); }, - child: Center( - child: SingleChildScrollView( - child: Stack( - children: [ - Positioned.fill( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 10, - sigmaY: 10, - ), - child: Container( - color: Colors.transparent, - ), - ), + child: Stack( + children: [ + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 10.8731, + sigmaY: 10.8731, ), - Padding( + child: Container( + color: Colors.black.withOpacity(0.2), + ), + ), + ), + Center( + child: SingleChildScrollView( + child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -81,6 +82,9 @@ class MessageReactionsModal extends StatelessWidget { messageTheme: messageTheme, showReactions: false, showUsername: false, + showUserAvatar: message.user.id == ownId + ? DisplayWidget.gone + : DisplayWidget.show, showReplyIndicator: false, showTimestamp: false, showSendingIndicator: DisplayWidget.gone, @@ -95,9 +99,9 @@ class MessageReactionsModal extends StatelessWidget { ], ), ), - ], + ), ), - ), + ], ), ); } diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 504864b2..cc959a35 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -220,8 +220,8 @@ class StreamChatThemeData { return StreamChatThemeData( accentColor: accentColor, primaryColor: isDark ? Colors.black : Colors.white, - primaryIconTheme: - IconThemeData(color: isDark ? Colors.white : Colors.black), + primaryIconTheme: IconThemeData( + color: isDark ? Colors.white : Colors.black.withOpacity(.5)), defaultChannelImage: (context, channel) => SizedBox(), backgroundColor: isDark ? Colors.black : Colors.white, defaultUserImage: (context, user) => Center( @@ -287,7 +287,7 @@ class StreamChatThemeData { ), ownMessageTheme: MessageTheme( messageText: TextStyle( - fontSize: 15, + fontSize: 14.5, color: isDark ? Colors.white : Colors.black, ), createdAt: TextStyle( @@ -320,7 +320,7 @@ class StreamChatThemeData { isDark ? Color(0xff191919) : Color(0xffEAEAEA), reactionsBorderColor: isDark ? Colors.black : Colors.white, messageText: TextStyle( - fontSize: 15, + fontSize: 14.5, color: isDark ? Colors.white : Colors.black, ), createdAt: TextStyle( From 5ec32086d3bb06840e9c4b0104aff6aff998f1b0 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 11:05:58 +0100 Subject: [PATCH 11/15] add badge on unread messages --- example/ios/Flutter/.last_build_id | 2 +- example/ios/Podfile.lock | 6 ++++++ example/ios/Runner.xcodeproj/project.pbxproj | 2 ++ example/ios/Runner/Info.plist | 4 ++++ example/pubspec.yaml | 2 +- lib/src/message_actions_modal.dart | 7 +++++-- lib/src/message_input.dart | 22 +++++++++++++------- lib/src/stream_chat.dart | 8 +++++++ pubspec.yaml | 1 + 9 files changed, 43 insertions(+), 11 deletions(-) diff --git a/example/ios/Flutter/.last_build_id b/example/ios/Flutter/.last_build_id index 171fde31..661f8167 100644 --- a/example/ios/Flutter/.last_build_id +++ b/example/ios/Flutter/.last_build_id @@ -1 +1 @@ -0289cdadbd29bab804f275e3c5907d07 \ No newline at end of file +89eb023669fee58472de747080d78b5a \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index d22f1e0d..1e268608 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -80,6 +80,8 @@ PODS: - Flutter (1.0.0) - flutter_apns (0.0.1): - Flutter + - flutter_app_badger (0.0.1): + - Flutter - flutter_keyboard_visibility (0.0.1): - Flutter - flutter_local_notifications (0.0.1): @@ -160,6 +162,7 @@ DEPENDENCIES: - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) - flutter_apns (from `.symlinks/plugins/flutter_apns/ios`) + - flutter_app_badger (from `.symlinks/plugins/flutter_app_badger/ios`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - image_picker (from `.symlinks/plugins/image_picker/ios`) @@ -207,6 +210,8 @@ EXTERNAL SOURCES: :path: Flutter flutter_apns: :path: ".symlinks/plugins/flutter_apns/ios" + flutter_app_badger: + :path: ".symlinks/plugins/flutter_app_badger/ios" flutter_keyboard_visibility: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" flutter_local_notifications: @@ -244,6 +249,7 @@ SPEC CHECKSUMS: FirebaseMessaging: 29543feb343b09546ab3aa04d008ee8595b43c44 Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_apns: f516b118e423fe7c0a38771180549c4d6cb67c2f + flutter_app_badger: 65de4d6f0c34a891df49e6cfb8a1c0496426fa68 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index db80aaed..6d377561 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -322,6 +322,7 @@ "${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework", "${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework", "${BUILT_PRODUCTS_DIR}/flutter_apns/flutter_apns.framework", + "${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework", "${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework", "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", "${BUILT_PRODUCTS_DIR}/image_picker/image_picker.framework", @@ -350,6 +351,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_apns.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker.framework", diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index ea713691..6c2c8e27 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -54,5 +54,9 @@ UIViewControllerBasedStatusBarAppearance + UIBackgroundModes + + remote-notification + diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 9a6554e6..fc96b07a 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.31+33 +version: 1.0.33+35 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index 7ee4311c..ce680d34 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -218,13 +218,16 @@ class MessageActionsModal extends StatelessWidget { StreamIcons.edit, size: 22, color: - StreamChatTheme.of(context).primaryIconTheme.color, + StreamChatTheme.of(context).primaryIconTheme.color, ), onPressed: () {}, ), Text( 'Edit message', - style: Theme.of(context).textTheme.headline6.copyWith(fontWeight: FontWeight.bold), + style: Theme.of(context) + .textTheme + .headline6 + .copyWith(fontWeight: FontWeight.bold), ), IconButton( icon: Icon( diff --git a/lib/src/message_input.dart b/lib/src/message_input.dart index 30910924..d03a61bc 100644 --- a/lib/src/message_input.dart +++ b/lib/src/message_input.dart @@ -192,7 +192,7 @@ class MessageInputState extends State { padding: const EdgeInsets.all(8.0), child: _buildTextField(context), ), - if(widget.parentMessage != null) + if (widget.parentMessage != null) Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: _buildDmCheckbox(), @@ -222,7 +222,11 @@ class MessageInputState extends State { Widget _buildDmCheckbox() { return Row( children: [ - Checkbox(value: _sendAsDm, onChanged: (val) => setState(() {_sendAsDm = val;})), + Checkbox( + value: _sendAsDm, + onChanged: (val) => setState(() { + _sendAsDm = val; + })), Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Text('Send also as direct message'), @@ -316,9 +320,11 @@ class MessageInputState extends State { var matchedCommandsList = StreamChannel.of(context) .channel .config - .commands.where((element) => element.name == s.substring(1)).toList(); + .commands + .where((element) => element.name == s.substring(1)) + .toList(); - if(matchedCommandsList.length == 1) { + if (matchedCommandsList.length == 1) { _chosenCommand = matchedCommandsList[0]; textEditingController.clear(); _messageIsPresent = false; @@ -796,8 +802,8 @@ class MessageInputState extends State { return Center( child: InkWell( child: Padding( - padding: EdgeInsets.only( - left: 8.0, right: padding, top: 8.0, bottom: 8.0), + padding: + EdgeInsets.only(left: 8.0, right: padding, top: 8.0, bottom: 8.0), child: Icon(StreamIcons.attach), ), onTap: () { @@ -1053,7 +1059,9 @@ class MessageInputState extends State { child: Transform.rotate( angle: widget.editMessage == null ? -pi / 2 : 0, child: Icon( - widget.editMessage == null ? StreamIcons.send_message : StreamIcons.check_send, + widget.editMessage == null + ? StreamIcons.send_message + : StreamIcons.check_send, color: StreamChatTheme.of(context).accentColor, ), ), diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index b22c257c..c3b971a7 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_app_badger/flutter_app_badger.dart'; import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; @@ -186,6 +187,13 @@ class StreamChatState extends State with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); + client.state.totalUnreadCountStream.listen((count) { + if (count > 0) { + FlutterAppBadger.updateBadgeCount(count); + } else { + FlutterAppBadger.removeBadge(); + } + }); } StreamSubscription _newMessageSubscription; diff --git a/pubspec.yaml b/pubspec.yaml index edd19589..7c92406d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,6 +11,7 @@ environment: dependencies: flutter: sdk: flutter + flutter_app_badger: ^1.1.2 photo_view: ^0.10.1 rxdart: ^0.24.1 jiffy: ^3.0.1 From f361d7f7f5a80b4abf8167be7d9e6d0135f60578 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 14:12:59 +0100 Subject: [PATCH 12/15] fix tests --- lib/src/stream_chat.dart | 2 +- test/src/message_reaction_modal_test.dart | 12 ++++++++-- test/src/reaction_bubble_test.dart | 28 +++++++++++++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/lib/src/stream_chat.dart b/lib/src/stream_chat.dart index 4231dab2..e32c7fa1 100644 --- a/lib/src/stream_chat.dart +++ b/lib/src/stream_chat.dart @@ -178,7 +178,7 @@ class StreamChatState extends State with WidgetsBindingObserver { void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); - client.state.totalUnreadCountStream.listen((count) { + client.state?.totalUnreadCountStream?.listen((count) { if (count > 0) { FlutterAppBadger.updateBadgeCount(count); } else { diff --git a/test/src/message_reaction_modal_test.dart b/test/src/message_reaction_modal_test.dart index e3972780..e270793e 100644 --- a/test/src/message_reaction_modal_test.dart +++ b/test/src/message_reaction_modal_test.dart @@ -10,13 +10,21 @@ void main() { testWidgets( 'it should show one thumbs from the picker', (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); final themeData = ThemeData(); + + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + final streamTheme = StreamChatThemeData.getDefaultTheme(themeData); + await tester.pumpWidget( MaterialApp( theme: themeData, - home: StreamChatTheme( - data: streamTheme, + home: StreamChat( + client: client, + streamChatThemeData: streamTheme, child: MessageReactionsModal( message: Message( id: 'test', diff --git a/test/src/reaction_bubble_test.dart b/test/src/reaction_bubble_test.dart index dc0381de..c524061c 100644 --- a/test/src/reaction_bubble_test.dart +++ b/test/src/reaction_bubble_test.dart @@ -1,8 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; +import 'mocks.dart'; + void main() { testWidgets( 'it should show no reactions', @@ -29,17 +32,25 @@ void main() { testWidgets( 'it should show a thumb up', (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); final themeData = ThemeData(); + + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + await tester.pumpWidget( MaterialApp( theme: themeData, - home: StreamChatTheme( - data: StreamChatThemeData.getDefaultTheme(themeData), + home: StreamChat( + client: client, + streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData), child: Container( child: ReactionBubble( reactions: [ Reaction( type: 'thumbs_up', + user: User(id: 'test'), ), ], borderColor: Colors.black, @@ -56,20 +67,29 @@ void main() { testWidgets( 'it should show two reactions', (WidgetTester tester) async { + final client = MockClient(); + final clientState = MockClientState(); final themeData = ThemeData(); + + when(client.state).thenReturn(clientState); + when(clientState.user).thenReturn(OwnUser(id: 'user-id')); + await tester.pumpWidget( MaterialApp( theme: themeData, - home: StreamChatTheme( - data: StreamChatThemeData.getDefaultTheme(themeData), + home: StreamChat( + client: client, + streamChatThemeData: StreamChatThemeData.getDefaultTheme(themeData), child: Container( child: ReactionBubble( reactions: [ Reaction( type: 'thumbs_up', + user: User(id: 'test'), ), Reaction( type: 'love', + user: User(id: 'test'), ), ], borderColor: Colors.black, From fc52942dab023c1910115973638b01b02fd5ef18 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 14:46:43 +0100 Subject: [PATCH 13/15] update dependencies --- example/android/app/build.gradle | 2 +- example/pubspec.yaml | 2 +- lib/src/message_text.dart | 2 +- pubspec.yaml | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index dda667cf..4fd90eac 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -39,7 +39,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.example.example" - minSdkVersion 16 + minSdkVersion 21 targetSdkVersion 28 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/example/pubspec.yaml b/example/pubspec.yaml index fc96b07a..057208c9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.33+35 +version: 1.0.34+36 environment: sdk: ">=2.2.2 <3.0.0" diff --git a/lib/src/message_text.dart b/lib/src/message_text.dart index 2ee6a6f8..ed636a57 100644 --- a/lib/src/message_text.dart +++ b/lib/src/message_text.dart @@ -24,7 +24,7 @@ class MessageText extends StatelessWidget { final text = _replaceMentions(message.text); return MarkdownBody( data: text, - onTapLink: (link) { + onTapLink: (text, link, title) { if (link.startsWith('@')) { final mentionedUser = message.mentionedUsers.firstWhere( (u) => '@${u.name.replaceAll(' ', '')}' == link, diff --git a/pubspec.yaml b/pubspec.yaml index 548dc624..99db379b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,11 +17,11 @@ dependencies: jiffy: ^3.0.1 flutter_portal: ^0.3.0 cached_network_image: ^2.2.0+1 - flutter_markdown: ^0.4.2 + flutter_markdown: ^0.5.0 url_launcher: ^5.4.11 - video_player: ^0.10.11+1 + video_player: ^0.10.12+5 chewie: ^0.9.10 - file_picker: ^2.0.0 + file_picker: ^2.0.8+1 image_picker: ^0.6.7+2 flutter_keyboard_visibility: ^3.2.1 stream_chat: ^0.2.10 From fab4414b92f2a8fb8bf0544bbe39ff21638c7954 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 15:16:53 +0100 Subject: [PATCH 14/15] fix android build --- example/android/app/build.gradle | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 4fd90eac..474bfd75 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -31,9 +31,9 @@ android { sourceSets { main.java.srcDirs += 'src/main/kotlin' } - lintOptions { disable 'InvalidPackage' + checkReleaseBuilds false } defaultConfig { diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 057208c9..c885e55b 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.34+36 +version: 1.0.35+37 environment: sdk: ">=2.2.2 <3.0.0" From 1bd883caf3960ee4fa27da2fa774cf5aff3e2f60 Mon Sep 17 00:00:00 2001 From: Salvatore Giordano Date: Wed, 28 Oct 2020 15:44:54 +0100 Subject: [PATCH 15/15] fix android build --- example/android/build.gradle | 2 +- example/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/android/build.gradle b/example/android/build.gradle index e1cfea50..8c57e18a 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -6,7 +6,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.1.0' + classpath 'com.android.tools.build:gradle:3.6.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath 'com.google.gms:google-services:4.3.2' } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index c885e55b..c73804eb 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,6 +1,6 @@ name: example description: A new Flutter project. -version: 1.0.35+37 +version: 1.0.36+38 environment: sdk: ">=2.2.2 <3.0.0"