From cb69dd036a33b690f2ea9998c1fbff1652ceb6ef Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 12:02:17 +0530 Subject: [PATCH 01/18] [Reaction Bubble] Fix tail alignment Signed-off-by: Sahil Kumar --- lib/src/reaction_bubble.dart | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index d8f8c623..5f416bab 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -134,16 +134,11 @@ class ReactionBubble extends StatelessWidget { borderColor, ), ); - - if (!flipTail) { - return tail; - } else { - return Transform( - transform: Matrix4.rotationY(pi), - alignment: Alignment.center, - child: tail, - ); - } + return Transform( + transform: Matrix4.rotationY(flipTail ? 0 : pi), + alignment: Alignment.center, + child: tail, + ); } } From b9ae0eeab10615be0bab0af2374120b6cf24d053 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 12:02:55 +0530 Subject: [PATCH 02/18] Change `themeMode` to `ThemeMode.system` Signed-off-by: Sahil Kumar --- example/lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index e34252fd..5f4e001d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -74,7 +74,7 @@ class MyApp extends StatelessWidget { debugShowCheckedModeBanner: false, theme: ThemeData.light(), darkTheme: ThemeData.dark(), - themeMode: ThemeMode.dark, + themeMode: ThemeMode.system, onGenerateRoute: AppRoutes.generateRoute, initialRoute: client.state.user == null ? Routes.CHOOSE_USER : Routes.HOME, From 91feed9bace0f8a928ac083c648ff4597b9aeeb7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 14:19:24 +0530 Subject: [PATCH 03/18] [MessageActionsModal] Fix various alignment, size and color issues Signed-off-by: Sahil Kumar --- lib/src/message_actions_modal.dart | 207 ++++++++++++++++++----------- lib/src/message_widget.dart | 26 ++-- lib/src/reaction_picker.dart | 103 +++++++------- lib/src/stream_chat_theme.dart | 32 +---- 4 files changed, 199 insertions(+), 169 deletions(-) diff --git a/lib/src/message_actions_modal.dart b/lib/src/message_actions_modal.dart index c7ff56e0..d7497676 100644 --- a/lib/src/message_actions_modal.dart +++ b/lib/src/message_actions_modal.dart @@ -1,3 +1,4 @@ +import 'dart:math'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -92,8 +93,9 @@ class MessageActionsModal extends StatelessWidget { child: Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.stretch, + crossAxisAlignment: reverse + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, children: [ if (showReactions && (message.status == MessageSendingStatus.SENT || @@ -143,7 +145,6 @@ class MessageActionsModal extends StatelessWidget { ), ); }), - SizedBox(height: 8), TweenAnimationBuilder( tween: Tween(begin: 0.0, end: 1.0), duration: Duration(milliseconds: 300), @@ -153,47 +154,56 @@ class MessageActionsModal extends StatelessWidget { transform: Matrix4.identity() ..scale(val) ..rotateZ(-1.0 + val), - alignment: Alignment.topRight, + alignment: reverse + ? Alignment.topRight + : Alignment.topLeft, child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 48.0, + padding: EdgeInsets.only( + right: reverse ? 16 : 0, + left: reverse ? 0 : 48, ), - child: Material( - color: StreamChatTheme.of(context) - .colorTheme - .whiteSnow, - 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 (showThreadReply && - (message.status == - MessageSendingStatus.SENT || - message.status == null) && - message.parentId == null) - _buildThreadReplyButton(context), - if (showResendMessage) - _buildResendMessage(context), - if (showEditMessage) - _buildEditMessage(context), - if (showDeleteMessage) - _buildDeleteButton(context), - if (showCopyMessage) - _buildCopyButton(context), - ], - ).toList(), + child: SizedBox( + width: MediaQuery.of(context).size.width * 0.75, + child: Material( + color: StreamChatTheme.of(context) + .colorTheme + .whiteSnow, + clipBehavior: Clip.hardEdge, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.stretch, + children: ListTile.divideTiles( + color: StreamChatTheme.of(context) + .colorTheme + .greyWhisper, + context: context, + tiles: [ + if (showReply && + (message.status == + MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildReplyButton(context), + if (showThreadReply && + (message.status == + MessageSendingStatus.SENT || + message.status == null) && + message.parentId == null) + _buildThreadReplyButton(context), + if (showResendMessage) + _buildResendMessage(context), + if (showEditMessage) + _buildEditMessage(context), + if (showCopyMessage) + _buildCopyButton(context), + if (showDeleteMessage) + _buildDeleteButton(context), + ], + ).toList(), + ), ), ), ), @@ -211,12 +221,18 @@ class MessageActionsModal extends StatelessWidget { Widget _buildReplyButton(BuildContext context) { return ListTile( - title: Text( - 'Reply', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.reply( - color: StreamChatTheme.of(context).primaryIconTheme.color, + dense: true, + title: Row( + children: [ + StreamSvgIcon.reply( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Reply', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () { Navigator.pop(context); @@ -230,13 +246,21 @@ class MessageActionsModal extends StatelessWidget { Widget _buildDeleteButton(BuildContext context) { final isDeleteFailed = message.status == MessageSendingStatus.FAILED_DELETE; return ListTile( - title: Text( - isDeleteFailed ? 'Retry deleting message' : 'Delete message', - style: - Theme.of(context).textTheme.headline6.copyWith(color: Colors.red), - ), - leading: StreamSvgIcon.delete( - color: Colors.red, + dense: true, + title: Row( + children: [ + StreamSvgIcon.delete( + color: Colors.red, + ), + const SizedBox(width: 16), + Text( + isDeleteFailed ? 'Retry Deleting Message' : 'Delete Message', + style: StreamChatTheme.of(context) + .textTheme + .headline + .copyWith(color: Colors.red), + ), + ], ), onTap: () { Navigator.pop(context); @@ -250,12 +274,19 @@ class MessageActionsModal extends StatelessWidget { Widget _buildCopyButton(BuildContext context) { return ListTile( - title: Text( - 'Copy message', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.copy( - color: StreamChatTheme.of(context).primaryIconTheme.color, + dense: true, + title: Row( + children: [ + StreamSvgIcon.copy( + size: 24, + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Copy Message', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () async { await Clipboard.setData(ClipboardData(text: message.text)); @@ -266,12 +297,18 @@ class MessageActionsModal extends StatelessWidget { Widget _buildEditMessage(BuildContext context) { return ListTile( - title: Text( - 'Edit message', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.edit( - color: StreamChatTheme.of(context).primaryIconTheme.color, + dense: true, + title: Row( + children: [ + StreamSvgIcon.edit( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Edit Message', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () async { Navigator.pop(context); @@ -283,12 +320,18 @@ class MessageActionsModal extends StatelessWidget { Widget _buildResendMessage(BuildContext context) { final isUpdateFailed = message.status == MessageSendingStatus.FAILED_UPDATE; return ListTile( - title: Text( - isUpdateFailed ? 'Resend edited message' : 'Resend', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.circle_up( - color: StreamChatTheme.of(context).colorTheme.accentBlue, + dense: true, + title: Row( + children: [ + StreamSvgIcon.circle_up( + color: StreamChatTheme.of(context).colorTheme.accentBlue, + ), + const SizedBox(width: 16), + Text( + isUpdateFailed ? 'Resend Edited Message' : 'Resend', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () { Navigator.pop(context); @@ -374,12 +417,18 @@ class MessageActionsModal extends StatelessWidget { Widget _buildThreadReplyButton(BuildContext context) { return ListTile( - title: Text( - 'Thread reply', - style: Theme.of(context).textTheme.headline6, - ), - leading: StreamSvgIcon.thread( - color: StreamChatTheme.of(context).primaryIconTheme.color, + dense: true, + title: Row( + children: [ + StreamSvgIcon.thread( + color: StreamChatTheme.of(context).primaryIconTheme.color, + ), + const SizedBox(width: 16), + Text( + 'Thread Reply', + style: StreamChatTheme.of(context).textTheme.headline, + ), + ], ), onTap: () { Navigator.pop(context); diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 1200f38d..5acf473b 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -423,10 +423,12 @@ class _MessageWidgetState extends State { widget.reverse ? pi : 0), child: CustomPaint( painter: ReactionBubblePainter( - widget.messageTheme - .reactionsBackgroundColor, - widget.messageTheme - .reactionsBorderColor, + StreamChatTheme.of(context) + .colorTheme + .white, + StreamChatTheme.of(context) + .colorTheme + .white, ), ), ), @@ -492,18 +494,16 @@ class _MessageWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ StreamSvgIcon.eye( - color: - StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), + color: StreamChatTheme.of(context).colorTheme.grey, size: 16.0, ), SizedBox(width: 8.0), Text( 'Only visible to you', - style: StreamChatTheme.of(context).textTheme.footnote.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(0.5)), + style: StreamChatTheme.of(context) + .textTheme + .footnote + .copyWith(color: StreamChatTheme.of(context).colorTheme.grey), ), ], ), @@ -754,9 +754,7 @@ class _MessageWidgetState extends State { side: widget.attachmentBorderSide ?? widget.borderSide ?? BorderSide( - color: Theme.of(context).brightness == Brightness.dark - ? StreamChatTheme.of(context).colorTheme.white.withAlpha(24) - : StreamChatTheme.of(context).colorTheme.black.withAlpha(24), + color: StreamChatTheme.of(context).colorTheme.greyGainsboro, ), borderRadius: widget.attachmentBorderRadiusGeometry ?? widget.borderRadiusGeometry ?? diff --git a/lib/src/reaction_picker.dart b/lib/src/reaction_picker.dart index 9344b386..c5c42bd1 100644 --- a/lib/src/reaction_picker.dart +++ b/lib/src/reaction_picker.dart @@ -58,62 +58,65 @@ class _ReactionPickerState extends State return Transform.scale( scale: val, child: Material( - color: widget.messageTheme.reactionsBackgroundColor, + color: StreamChatTheme.of(context).colorTheme.white, clipBehavior: Clip.hardEdge, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.end, - mainAxisSize: MainAxisSize.min, - children: reactionIcons.map((reactionIcon) { - final ownReactionIndex = widget.message.ownReactions - ?.indexWhere((reaction) => - reaction.type == reactionIcon.type) ?? - -1; - var index = reactionIcons.indexOf(reactionIcon); + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.end, + mainAxisSize: MainAxisSize.min, + children: reactionIcons.map((reactionIcon) { + final ownReactionIndex = widget.message.ownReactions + ?.indexWhere((reaction) => + reaction.type == reactionIcon.type) ?? + -1; + var index = reactionIcons.indexOf(reactionIcon); - return IconButton( - iconSize: 24, - icon: AnimatedBuilder( - animation: animations[index], - builder: (context, val) { - return Transform( - transform: Matrix4.identity() - ..scale(animations[index].value, - animations[index].value) - ..rotateZ(1.0 - animations[index].value), - child: StreamSvgIcon( - assetName: reactionIcon.assetName, - height: animations[index].value * 24.0, - width: animations[index].value * 24.0, - color: ownReactionIndex != -1 - ? StreamChatTheme.of(context) - .colorTheme - .accentBlue - : Theme.of(context) - .iconTheme - .color - .withOpacity(.5), - ), + return IconButton( + iconSize: 24, + icon: AnimatedBuilder( + animation: animations[index], + builder: (context, val) { + return Transform( + transform: Matrix4.identity() + ..scale(animations[index].value, + animations[index].value) + ..rotateZ(1.0 - animations[index].value), + child: StreamSvgIcon( + assetName: reactionIcon.assetName, + height: animations[index].value * 24.0, + width: animations[index].value * 24.0, + color: ownReactionIndex != -1 + ? StreamChatTheme.of(context) + .colorTheme + .accentBlue + : Theme.of(context) + .iconTheme + .color + .withOpacity(.5), + ), + ); + }), + onPressed: () { + if (ownReactionIndex != -1) { + removeReaction( + context, + widget.message.ownReactions[ownReactionIndex], ); - }), - onPressed: () { - if (ownReactionIndex != -1) { - removeReaction( - context, - widget.message.ownReactions[ownReactionIndex], - ); - } else { - sendReaction( - context, - reactionIcon.type, - ); - } - }, - ); - }).toList(), + } else { + sendReaction( + context, + reactionIcon.type, + ); + } + }, + ); + }).toList(), + ), ), ), ); diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart index 439bd5ef..c6d2d72f 100644 --- a/lib/src/stream_chat_theme.dart +++ b/lib/src/stream_chat_theme.dart @@ -228,19 +228,9 @@ class StreamChatThemeData { inputBackground: colorTheme.white.withAlpha(12), ), ownMessageTheme: MessageTheme( - messageText: TextStyle( - fontSize: 14.5, - color: colorTheme.black, - ), - createdAt: TextStyle( - color: colorTheme.black.withOpacity(.5), - fontSize: 12, - ), - replies: TextStyle( - color: accentColor, - fontWeight: FontWeight.w600, - fontSize: 12, - ), + messageText: textTheme.body, + createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), + replies: textTheme.footnoteBold.copyWith(color: accentColor), messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: colorTheme.greyWhisper, @@ -259,19 +249,9 @@ class StreamChatThemeData { otherMessageTheme: MessageTheme( reactionsBackgroundColor: colorTheme.greyGainsboro, reactionsBorderColor: colorTheme.white, - messageText: TextStyle( - fontSize: 14.5, - color: colorTheme.black, - ), - createdAt: TextStyle( - color: colorTheme.black.withOpacity(.5), - fontSize: 12, - ), - replies: TextStyle( - color: accentColor, - fontWeight: FontWeight.w600, - fontSize: 12, - ), + messageText: textTheme.body, + createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), + replies: textTheme.footnoteBold.copyWith(color: accentColor), messageLinks: TextStyle( color: accentColor, ), From b9f5dc395cc709907b6c41d76b5ad7d180de2bc4 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 14:33:53 +0530 Subject: [PATCH 04/18] [GroupInfoScreen] Show chat owner always on top of the member list Signed-off-by: Sahil Kumar --- example/lib/group_info_screen.dart | 34 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/example/lib/group_info_screen.dart b/example/lib/group_info_screen.dart index 985fe62d..ed5f2c61 100644 --- a/example/lib/group_info_screen.dart +++ b/example/lib/group_info_screen.dart @@ -169,12 +169,18 @@ class _GroupInfoScreenState extends State { } Widget _buildMembers(List members) { - int groupMemberListLength; + final groupMembers = members + ..sort((prev, curr) { + if (curr.role == 'owner') return 1; + return 0; + }); + + int groupMembersLength; if (listExpanded) { - groupMemberListLength = members.length; + groupMembersLength = groupMembers.length; } else { - groupMemberListLength = members.length > 6 ? 6 : members.length; + groupMembersLength = groupMembers.length > 6 ? 6 : groupMembers.length; } return Column( @@ -182,15 +188,15 @@ class _GroupInfoScreenState extends State { ListView.builder( shrinkWrap: true, physics: NeverScrollableScrollPhysics(), - itemCount: groupMemberListLength, - itemBuilder: (context, position) { + itemCount: groupMembersLength, + itemBuilder: (context, index) { + final member = groupMembers[index]; return Material( child: InkWell( onTap: () { - var userMember = members.firstWhere( + var userMember = groupMembers.firstWhere( (e) => e.user.id == StreamChat.of(context).user.id); - _showUserInfoModal( - members[position].user, userMember.role == 'owner'); + _showUserInfoModal(member.user, userMember.role == 'owner'); }, child: Container( height: 65.0, @@ -202,7 +208,7 @@ class _GroupInfoScreenState extends State { padding: const EdgeInsets.symmetric( horizontal: 8.0, vertical: 12.0), child: UserAvatar( - user: members[position].user, + user: member.user, constraints: BoxConstraints( maxHeight: 40.0, maxWidth: 40.0), ), @@ -213,14 +219,14 @@ class _GroupInfoScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - members[position].user.name, + member.user.name, style: TextStyle(fontWeight: FontWeight.bold), ), SizedBox( height: 1.0, ), Text( - _getLastSeen(members[position].user), + _getLastSeen(member.user), style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -233,7 +239,7 @@ class _GroupInfoScreenState extends State { Padding( padding: const EdgeInsets.all(8.0), child: Text( - members[position].role == 'owner' ? 'Owner' : '', + member.role == 'owner' ? 'Owner' : '', style: TextStyle( color: StreamChatTheme.of(context) .colorTheme @@ -257,7 +263,7 @@ class _GroupInfoScreenState extends State { ); }, ), - if (groupMemberListLength != members.length) + if (groupMembersLength != groupMembers.length) InkWell( onTap: () { setState(() { @@ -287,7 +293,7 @@ class _GroupInfoScreenState extends State { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - '${members.length - groupMemberListLength} more', + '${members.length - groupMembersLength} more', style: TextStyle( color: StreamChatTheme.of(context) .colorTheme From 7d938b2e4073b5ef4894f37762dad50d0e5a6fc2 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 14:37:32 +0530 Subject: [PATCH 05/18] [ChannelMediaDisplayScreen] Hide link attachments Signed-off-by: Sahil Kumar --- lib/src/channel_media_display_screen.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/channel_media_display_screen.dart b/lib/src/channel_media_display_screen.dart index cd5238bc..ebc95516 100644 --- a/lib/src/channel_media_display_screen.dart +++ b/lib/src/channel_media_display_screen.dart @@ -142,7 +142,9 @@ class _ChannelMediaDisplayScreenState extends State { for (var item in snapshot.data) { item.message.attachments - .where((e) => e.type == 'image' || e.type == 'video') + .where((e) => + (e.type == 'image' || e.type == 'video') && + e.ogScrapeUrl == null) .forEach((e) { VideoPlayerController controller; if (e.type == 'video') { From 2f3e6ced0d5dfd7c3952b99c33dc25dcb050fb79 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 16:29:13 +0530 Subject: [PATCH 06/18] [MessageReactionsModal] Fix reaction bubble alignment Signed-off-by: Sahil Kumar --- lib/src/message_reactions_modal.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 375f5e0c..0527710a 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -227,16 +227,19 @@ class MessageReactionsModal extends StatelessWidget { ), Positioned( child: Align( - alignment: Alignment.centerLeft, + alignment: reverse + ? Alignment.centerRight + : Alignment.centerLeft, child: ReactionBubble( reactions: [reaction], + flipTail: !reverse, borderColor: messageTheme.reactionsBorderColor, backgroundColor: messageTheme.reactionsBackgroundColor, highlightOwnReactions: false, ), ), - bottom: 4, + bottom: 6, left: isCurrentUser ? 0 : null, right: isCurrentUser ? 0 : null, ), From 11bb372011f555e4e99a090a6b008d7103a34746 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 16:50:46 +0530 Subject: [PATCH 07/18] [MessageReactionsModal] Fix padding Signed-off-by: Sahil Kumar --- lib/src/message_reactions_modal.dart | 36 ++++++++++++---------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index 0527710a..b8ad1b4e 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -127,7 +127,6 @@ class MessageReactionsModal extends StatelessWidget { ), ); }), - SizedBox(height: 8), if (message.latestReactions?.isNotEmpty == true) _buildReactionCard(context), ], @@ -152,27 +151,21 @@ class MessageReactionsModal extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(16.0), - child: Text( + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( 'Message Reactions', - style: Theme.of(context).textTheme.headline6, + style: StreamChatTheme.of(context).textTheme.headlineBold, ), - ), - Flexible( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.only( - left: 18, - right: 18, - bottom: 26, - ), + const SizedBox(height: 16), + Flexible( + child: SingleChildScrollView( child: Wrap( spacing: 16, - runSpacing: 22, + runSpacing: 16, alignment: WrapAlignment.start, children: message.latestReactions .map((e) => _buildReaction( @@ -184,8 +177,8 @@ class MessageReactionsModal extends StatelessWidget { ), ), ), - ), - ], + ], + ), ), ), ); @@ -245,9 +238,10 @@ class MessageReactionsModal extends StatelessWidget { ), ], ), + const SizedBox(height: 8), Text( reaction.user.name, - style: Theme.of(context).textTheme.subtitle2, + style: StreamChatTheme.of(context).textTheme.footnoteBold, textAlign: TextAlign.center, ), ], From 1dc7a06991245c27561333debfb9703e14bcfc40 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 17:30:41 +0530 Subject: [PATCH 08/18] [MessageListView] Fix attachment corner radius Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 9f4cbc0d..e8c4923f 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -759,6 +759,11 @@ class _MessageListViewState extends State { final isThreadMessage = widget.parentMessage != null || message?.showInChannel == true; + final hasFileAttachment = + message.attachments.any((it) => it.type == 'file'); + + final attachmentBorderRadius = hasFileAttachment ? 12.0 : 14.0; + Widget child = MessageWidget( key: ValueKey('MESSAGE-${message.id}'), message: message, @@ -804,10 +809,10 @@ class _MessageListViewState extends State { onThreadTap: _onThreadTap, onReplyTap: widget.onReplyTap, attachmentBorderRadiusGeometry: BorderRadius.only( - topLeft: Radius.circular(16), - bottomLeft: Radius.circular(!isNextUser ? 0 : 16), - topRight: Radius.circular(16), - bottomRight: Radius.circular(16), + topLeft: Radius.circular(attachmentBorderRadius), + bottomLeft: Radius.circular(!isNextUser ? 0 : attachmentBorderRadius), + topRight: Radius.circular(attachmentBorderRadius), + bottomRight: Radius.circular(attachmentBorderRadius), ), attachmentPadding: const EdgeInsets.all(2), borderRadiusGeometry: BorderRadius.only( From c931e5142d57ab1b7331e4e7a6d1a5804af0d152 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 17:38:03 +0530 Subject: [PATCH 09/18] [DateDivider] Fix text case and add 1px vertical padding Signed-off-by: Sahil Kumar --- lib/src/date_divider.dart | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/src/date_divider.dart b/lib/src/date_divider.dart index 12070e51..c7cfe296 100644 --- a/lib/src/date_divider.dart +++ b/lib/src/date_divider.dart @@ -5,10 +5,12 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// It shows a date divider depending on the date difference class DateDivider extends StatelessWidget { final DateTime dateTime; + final bool uppercase; const DateDivider({ Key key, @required this.dateTime, + this.uppercase = false, }) : super(key: key); @override @@ -18,38 +20,37 @@ class DateDivider extends StatelessWidget { String dayInfo; if (Jiffy(createdAt).isSame(now, Units.DAY)) { - dayInfo = 'TODAY'; + dayInfo = 'Today'; } else if (Jiffy(createdAt) .isSame(now.subtract(Duration(days: 1)), Units.DAY)) { - dayInfo = 'YESTERDAY'; + dayInfo = 'Yesterday'; } else if (Jiffy(createdAt).isAfter( now.subtract(Duration(days: 7)), Units.DAY, )) { - dayInfo = createdAt.format('EEEE').toUpperCase(); + dayInfo = createdAt.format('EEEE'); } else if (Jiffy(createdAt).isAfter( Jiffy(now).subtract(years: 1), Units.DAY, )) { - dayInfo = createdAt.format('MMMM d').toUpperCase(); + dayInfo = createdAt.format('MMMM d'); } else { - dayInfo = createdAt.format('MMMM d').toUpperCase(); + dayInfo = createdAt.format('MMMM d'); } + if (uppercase) dayInfo = dayInfo.toUpperCase(); + return Center( child: Container( - padding: const EdgeInsets.symmetric(horizontal: 8), + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1), decoration: BoxDecoration( - color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5), - borderRadius: BorderRadius.circular( - 8, - ), + color: StreamChatTheme.of(context).colorTheme.overlayDark, + borderRadius: BorderRadius.circular(8), ), child: Text( dayInfo, - style: StreamChatTheme.of(context).textTheme.footnoteBold.copyWith( + style: StreamChatTheme.of(context).textTheme.footnote.copyWith( color: StreamChatTheme.of(context).colorTheme.white, - fontWeight: FontWeight.bold, ), ), ), From d074bf8d9f182f72e7f970c34d3138bd23159dc7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 19:42:27 +0530 Subject: [PATCH 10/18] Fix drawer tile splash Signed-off-by: Sahil Kumar --- example/lib/main.dart | 201 +++++++++++++++++++++--------------------- 1 file changed, 99 insertions(+), 102 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 5f4e001d..caaebaba 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -166,116 +166,113 @@ class _HomePageState extends State { Drawer _buildDrawer(BuildContext context, User user) { return Drawer( - child: Container( - color: StreamChatTheme.of(context).colorTheme.white, - child: SafeArea( - child: Padding( - padding: EdgeInsets.only( - top: MediaQuery.of(context).viewPadding.top + 8, - ), - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only( - bottom: 20.0, - left: 8, - ), - child: Row( - children: [ - UserAvatar( - user: user, - showOnlineStatus: false, - constraints: BoxConstraints.tight(Size.fromRadius(20)), - ), - Padding( - padding: const EdgeInsets.only(left: 16.0), - child: Text( - user.name, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - ), + child: SafeArea( + child: Padding( + padding: EdgeInsets.only( + top: MediaQuery.of(context).viewPadding.top + 8, + ), + child: Column( + children: [ + Padding( + padding: const EdgeInsets.only( + bottom: 20.0, + left: 8, ), - ListTile( - leading: StreamSvgIcon.penWrite( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - onTap: () { - Navigator.popAndPushNamed( - context, - Routes.NEW_CHAT, - ); - }, - title: Text( - 'New direct message', - style: TextStyle( - fontSize: 14.5, + child: Row( + children: [ + UserAvatar( + user: user, + showOnlineStatus: false, + constraints: BoxConstraints.tight(Size.fromRadius(20)), ), - ), - ), - ListTile( - leading: StreamSvgIcon.contacts( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - onTap: () { - Navigator.popAndPushNamed( - context, - Routes.NEW_GROUP_CHAT, - ); - }, - title: Text( - 'New group', - style: TextStyle( - fontSize: 14.5, - ), - ), - ), - Expanded( - child: Container( - alignment: Alignment.bottomCenter, - child: ListTile( - onTap: () async { - Navigator.pop(context); - - final secureStorage = FlutterSecureStorage(); - await secureStorage.deleteAll(); - - StreamChat.of(context).client.disconnect( - clearUser: true, - ); - - await Navigator.pushReplacementNamed( - context, - Routes.CHOOSE_USER, - ); - }, - leading: StreamSvgIcon.user( - color: StreamChatTheme.of(context) - .colorTheme - .black - .withOpacity(.5), - ), - title: Text( - 'Sign out', + Padding( + padding: const EdgeInsets.only(left: 16.0), + child: Text( + user.name, style: TextStyle( - fontSize: 14.5, + fontSize: 16, + fontWeight: FontWeight.bold, ), ), ), + ], + ), + ), + ListTile( + leading: StreamSvgIcon.penWrite( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + onTap: () { + Navigator.popAndPushNamed( + context, + Routes.NEW_CHAT, + ); + }, + title: Text( + 'New direct message', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + ListTile( + leading: StreamSvgIcon.contacts( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + onTap: () { + Navigator.popAndPushNamed( + context, + Routes.NEW_GROUP_CHAT, + ); + }, + title: Text( + 'New group', + style: TextStyle( + fontSize: 14.5, + ), + ), + ), + Expanded( + child: Container( + alignment: Alignment.bottomCenter, + child: ListTile( + onTap: () async { + Navigator.pop(context); + + final secureStorage = FlutterSecureStorage(); + await secureStorage.deleteAll(); + + StreamChat.of(context).client.disconnect( + clearUser: true, + ); + + await Navigator.pushReplacementNamed( + context, + Routes.CHOOSE_USER, + ); + }, + leading: StreamSvgIcon.user( + color: StreamChatTheme.of(context) + .colorTheme + .black + .withOpacity(.5), + ), + title: Text( + 'Sign out', + style: TextStyle( + fontSize: 14.5, + ), + ), ), ), - ], - ), + ), + ], ), ), ), From c14bcefe201b74ed59ba9d459a8bbc439bf2bf04 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 19:58:16 +0530 Subject: [PATCH 11/18] [QuotedMessageWidget] Remove bottom padding Signed-off-by: Sahil Kumar --- lib/src/quoted_message_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/quoted_message_widget.dart b/lib/src/quoted_message_widget.dart index 7c5dd512..c0439d46 100644 --- a/lib/src/quoted_message_widget.dart +++ b/lib/src/quoted_message_widget.dart @@ -111,7 +111,7 @@ class QuotedMessageWidget extends StatelessWidget { return InkWell( onTap: onTap, child: Padding( - padding: const EdgeInsets.only(top: 8, bottom: 6, right: 4, left: 8), + padding: const EdgeInsets.only(top: 8, right: 4, left: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.end, mainAxisSize: MainAxisSize.min, From a93c53335a841a2d89123a98427977b09d0a1c8b Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 20:12:03 +0530 Subject: [PATCH 12/18] [MessageReactionsModal] Remove ReactionCard additional card margin Signed-off-by: Sahil Kumar --- lib/src/message_reactions_modal.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/message_reactions_modal.dart b/lib/src/message_reactions_modal.dart index b8ad1b4e..702bb0ed 100644 --- a/lib/src/message_reactions_modal.dart +++ b/lib/src/message_reactions_modal.dart @@ -151,6 +151,7 @@ class MessageReactionsModal extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), + margin: EdgeInsets.zero, child: Padding( padding: const EdgeInsets.all(16), child: Column( From 6ed63fc8c773edbd1ed3076a13665abfc8aa0b44 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 21:47:18 +0530 Subject: [PATCH 13/18] [UrlAttachment] Remove extra imageUrl padding Signed-off-by: Sahil Kumar --- lib/src/url_attachment.dart | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/src/url_attachment.dart b/lib/src/url_attachment.dart index 1909fc33..81f89a01 100644 --- a/lib/src/url_attachment.dart +++ b/lib/src/url_attachment.dart @@ -24,10 +24,6 @@ class UrlAttachment extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - if (urlAttachment.imageUrl != null) - SizedBox( - height: 16.0, - ), if (urlAttachment.imageUrl != null) Container( clipBehavior: Clip.antiAliasWithSaveLayer, From a02aaaaa651971515cd6895365d1c7fd2e2153b1 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 22:48:37 +0530 Subject: [PATCH 14/18] [MessageListView] Refactor message separators Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 105 ++++++++++++++++++++------------- lib/src/message_widget.dart | 12 +++- 2 files changed, 75 insertions(+), 42 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index e8c4923f..7a568361 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -324,7 +324,7 @@ class _MessageListViewState extends State { onInBetweenOfPage: () { _inBetweenList = true; }, - child: ScrollablePositionedList.builder( + child: ScrollablePositionedList.separated( key: ValueKey(initialIndex + initialAlignment), itemPositionsListener: _itemPositionListener, addAutomaticKeepAlives: true, @@ -336,6 +336,45 @@ class _MessageListViewState extends State { itemCount: messages.length + 2 + (widget.parentMessage != null ? 1 : 0), + separatorBuilder: (context, i) { + if (i == messages.length) return Offstage(); + if (i == messages.length + 2) return Offstage(); + if (i == messages.length + 1) return Offstage(); + if (i == 0) return SizedBox(height: 30); + final message = messages[i]; + final nextMessage = i > 0 ? messages[i - 1] : null; + if (nextMessage != null && + !Jiffy(message.createdAt.toLocal()).isSame( + nextMessage.createdAt.toLocal(), + Units.DAY, + )) { + final divider = widget.dateDividerBuilder != null + ? widget.dateDividerBuilder( + nextMessage.createdAt.toLocal(), + ) + : DateDivider( + dateTime: nextMessage.createdAt.toLocal(), + ); + return Padding( + padding: const EdgeInsets.symmetric(vertical: 12.0), + child: divider, + ); + } + num timeDiff = 0; + if (nextMessage != null) { + timeDiff = Jiffy(nextMessage.createdAt.toLocal()).diff( + message.createdAt.toLocal(), + Units.MINUTE, + ); + } + final isNextUserSame = (i - 1 >= 0) && + message.user.id == messages[i - 1]?.user?.id; + final isThread = message.replyCount > 0; + if (timeDiff >= 1 || !isNextUserSame || isThread) { + return SizedBox(height: 8); + } + return SizedBox(height: 2); + }, itemBuilder: (context, i) { if (i == messages.length + 2) { if (widget.parentMessageBuilder != null) { @@ -383,7 +422,6 @@ class _MessageListViewState extends State { ); } final message = messages[i - 1]; - final nextMessage = (i - 1) > 0 ? messages[i - 2] : null; Widget messageWidget; @@ -419,27 +457,6 @@ class _MessageListViewState extends State { messageWidget = buildMessage(message, messages, i); } } - - if (nextMessage != null && - !Jiffy(message.createdAt.toLocal()).isSame( - nextMessage.createdAt.toLocal(), Units.DAY)) { - return Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - messageWidget, - Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: widget.dateDividerBuilder != null - ? widget.dateDividerBuilder( - nextMessage.createdAt.toLocal()) - : DateDivider( - dateTime: nextMessage.createdAt.toLocal(), - ), - ), - ], - ); - } - return messageWidget; }, ), @@ -740,8 +757,17 @@ class _MessageListViewState extends State { final userId = StreamChat.of(context).user.id; final isMyMessage = message.user.id == userId; - final isNextUser = - index - 2 >= 0 && message.user.id == messages[index - 2]?.user?.id; + final nextMessage = index - 2 >= 0 ? messages[index - 2] : null; + final isNextUserSame = + nextMessage != null && message.user.id == nextMessage.user.id; + + num timeDiff = 0; + if (nextMessage != null) { + timeDiff = Jiffy(nextMessage.createdAt.toLocal()).diff( + message.createdAt.toLocal(), + Units.MINUTE, + ); + } final channel = streamChannel.channel; final readList = channel.state?.read @@ -769,12 +795,7 @@ class _MessageListViewState extends State { message: message, reverse: isMyMessage, showReactions: !message.isDeleted, - padding: EdgeInsets.only( - left: 8.0, - right: 8.0, - bottom: index == 0 ? 30 : (isNextUser ? 2 : 7), - top: 3, - ), + padding: const EdgeInsets.symmetric(horizontal: 8.0), onQuotedMessageTap: (quotedMessageId) async { final scrollToIndex = () { final index = messages.indexWhere((m) => m.id == quotedMessageId); @@ -797,12 +818,13 @@ class _MessageListViewState extends State { }, showInChannelIndicator: widget.parentMessage == null, showThreadReplyIndicator: widget.parentMessage == null, - showUsername: !isMyMessage && !isNextUser, - showSendingIndicator: isMyMessage && - (index == 0 || message.status != MessageSendingStatus.SENT) - ? DisplayWidget.show - : DisplayWidget.hide, - showTimestamp: !isNextUser || readList?.isNotEmpty == true, + showUsername: !isMyMessage && (timeDiff >= 1 || !isNextUserSame), + showSendingIndicator: + isMyMessage && (index == 0 || timeDiff >= 1 || !isNextUserSame) + ? DisplayWidget.show + : DisplayWidget.hide, + showTimestamp: + !isNextUserSame || readList?.isNotEmpty == true || timeDiff >= 1, showEditMessage: isMyMessage, showDeleteMessage: isMyMessage, borderSide: isMyMessage ? BorderSide.none : null, @@ -810,20 +832,23 @@ class _MessageListViewState extends State { onReplyTap: widget.onReplyTap, attachmentBorderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(attachmentBorderRadius), - bottomLeft: Radius.circular(!isNextUser ? 0 : attachmentBorderRadius), + bottomLeft: Radius.circular( + timeDiff >= 1 || !isNextUserSame ? 0 : attachmentBorderRadius), topRight: Radius.circular(attachmentBorderRadius), bottomRight: Radius.circular(attachmentBorderRadius), ), attachmentPadding: const EdgeInsets.all(2), borderRadiusGeometry: BorderRadius.only( topLeft: Radius.circular(16), - bottomLeft: Radius.circular(!isNextUser ? 0 : 16), + bottomLeft: Radius.circular(timeDiff >= 1 || !isNextUserSame ? 0 : 16), topRight: Radius.circular(16), bottomRight: Radius.circular(16), ), showUserAvatar: isMyMessage ? DisplayWidget.gone - : (isNextUser ? DisplayWidget.hide : DisplayWidget.show), + : (timeDiff >= 1 || !isNextUserSame + ? DisplayWidget.show + : DisplayWidget.hide), messageTheme: isMyMessage ? StreamChatTheme.of(context).ownMessageTheme : StreamChatTheme.of(context).otherMessageTheme, diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 5acf473b..430be523 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -278,7 +278,7 @@ class _MessageWidgetState extends State { Widget build(BuildContext context) { final avatarWidth = widget.messageTheme.avatarTheme.constraints.maxWidth; var leftPadding = - widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 4.5; + widget.showUserAvatar != DisplayWidget.gone ? avatarWidth + 8.5 : 0.5; final isOnlyEmoji = widget.message.text.characters.every((c) => Emoji.byChar(c) != null); @@ -330,7 +330,7 @@ class _MessageWidgetState extends State { child: PortalEntry( portal: Container( transform: - Matrix4.translationValues(-16, 2, 0), + Matrix4.translationValues(-12, 0, 0), child: _buildReactionIndicator(context), constraints: BoxConstraints(maxWidth: 22 * 6.0), @@ -372,6 +372,14 @@ class _MessageWidgetState extends State { : Card( clipBehavior: Clip.antiAlias, elevation: 0.0, + margin: EdgeInsets.symmetric( + horizontal: + widget.showUserAvatar == + DisplayWidget + .gone + ? 0 + : 4.0, + ), shape: widget.shape ?? RoundedRectangleBorder( side: isOnlyEmoji && From beb0620daa1401db6cd6ef7ee3daa6799ae43bbf Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 23:07:48 +0530 Subject: [PATCH 15/18] fix test Signed-off-by: Sahil Kumar --- test/src/message_action_modal_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/message_action_modal_test.dart b/test/src/message_action_modal_test.dart index 0dcd8d87..7da2095d 100644 --- a/test/src/message_action_modal_test.dart +++ b/test/src/message_action_modal_test.dart @@ -42,10 +42,10 @@ void main() { await tester.pump(Duration(milliseconds: 1000)); expect(find.byKey(Key('MessageWidget')), findsOneWidget); - expect(find.text('Thread reply'), findsOneWidget); - expect(find.text('Edit message'), findsOneWidget); - expect(find.text('Delete message'), findsOneWidget); - expect(find.text('Copy message'), findsOneWidget); + expect(find.text('Thread Reply'), findsOneWidget); + expect(find.text('Edit Message'), findsOneWidget); + expect(find.text('Delete Message'), findsOneWidget); + expect(find.text('Copy Message'), findsOneWidget); }, ); testWidgets( From 02581739354e00e57b8864dcb9e0e7c0ba936378 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 23:35:38 +0530 Subject: [PATCH 16/18] [ReactionBubble] Add conditional horizontal padding Signed-off-by: Sahil Kumar --- lib/src/reaction_bubble.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/reaction_bubble.dart b/lib/src/reaction_bubble.dart index 5f416bab..9eee9997 100644 --- a/lib/src/reaction_bubble.dart +++ b/lib/src/reaction_bubble.dart @@ -27,7 +27,8 @@ class ReactionBubble extends StatelessWidget { @override Widget build(BuildContext context) { final reactionIcons = StreamChatTheme.of(context).reactionIcons; - final offset = reactions.length > 1 ? 16.0 : 2.0; + final totalReactions = reactions.length; + final offset = totalReactions > 1 ? 16.0 : 2.0; return Transform( transform: Matrix4.rotationY(reverse ? pi : 0), alignment: Alignment.center, @@ -37,7 +38,10 @@ class ReactionBubble extends StatelessWidget { Transform.translate( offset: Offset(reverse ? offset : -offset, 0), child: Container( - padding: const EdgeInsets.symmetric(vertical: 4), + padding: EdgeInsets.symmetric( + vertical: 4, + horizontal: totalReactions > 1 ? 4 : 0, + ), decoration: BoxDecoration( border: Border.all( color: borderColor, From 3dd451e511d7ffc89da4c46e5c7a311cb045707a Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 8 Jan 2021 23:37:55 +0530 Subject: [PATCH 17/18] [MessageListView] Remove unwanted null checks from separator logic Signed-off-by: Sahil Kumar --- lib/src/message_list_view.dart | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/src/message_list_view.dart b/lib/src/message_list_view.dart index 7a568361..415539b8 100644 --- a/lib/src/message_list_view.dart +++ b/lib/src/message_list_view.dart @@ -342,12 +342,11 @@ class _MessageListViewState extends State { if (i == messages.length + 1) return Offstage(); if (i == 0) return SizedBox(height: 30); final message = messages[i]; - final nextMessage = i > 0 ? messages[i - 1] : null; - if (nextMessage != null && - !Jiffy(message.createdAt.toLocal()).isSame( - nextMessage.createdAt.toLocal(), - Units.DAY, - )) { + final nextMessage = messages[i - 1]; + if (!Jiffy(message.createdAt.toLocal()).isSame( + nextMessage.createdAt.toLocal(), + Units.DAY, + )) { final divider = widget.dateDividerBuilder != null ? widget.dateDividerBuilder( nextMessage.createdAt.toLocal(), @@ -360,15 +359,14 @@ class _MessageListViewState extends State { child: divider, ); } - num timeDiff = 0; - if (nextMessage != null) { - timeDiff = Jiffy(nextMessage.createdAt.toLocal()).diff( - message.createdAt.toLocal(), - Units.MINUTE, - ); - } - final isNextUserSame = (i - 1 >= 0) && - message.user.id == messages[i - 1]?.user?.id; + final timeDiff = + Jiffy(nextMessage.createdAt.toLocal()).diff( + message.createdAt.toLocal(), + Units.MINUTE, + ); + + final isNextUserSame = + message.user.id == nextMessage.user?.id; final isThread = message.replyCount > 0; if (timeDiff >= 1 || !isNextUserSame || isThread) { return SizedBox(height: 8); From 8e285df0245f64a09a425f894435654830344b32 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 11 Jan 2021 12:38:29 +0530 Subject: [PATCH 18/18] [MessageWidget] Fix crossAxisAlignment Signed-off-by: Sahil Kumar --- lib/src/message_widget.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/message_widget.dart b/lib/src/message_widget.dart index 430be523..12137c64 100644 --- a/lib/src/message_widget.dart +++ b/lib/src/message_widget.dart @@ -403,7 +403,7 @@ class _MessageWidgetState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment - .start, + .end, mainAxisSize: MainAxisSize.min, children: [